diff --git a/.changeset/closed-exits-update.md b/.changeset/closed-exits-update.md new file mode 100644 index 00000000..cd77293c --- /dev/null +++ b/.changeset/closed-exits-update.md @@ -0,0 +1,10 @@ +--- +"@mrtdown/core": major +"@mrtdown/fs": patch +--- + +Require provenance dates on durable station layout records, add temporary exit +closure and non-boardable platform statuses, disambiguate repeated service +stops, validate platform mappings against service revisions active on each +platform's provenance date, and keep transfer endpoints as lightweight +references. diff --git a/data/station/ADM.json b/data/station/ADM.json index 0b228b65..616744a2 100644 --- a/data/station/ADM.json +++ b/data/station/ADM.json @@ -62,5 +62,77 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "ADM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 7" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ADM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 7" + ], + "paidArea": false + }, + { + "id": "ADM_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 7" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ADM_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 7" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "ADM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "ADM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/ALJ.json b/data/station/ALJ.json index 0d9c659a..16af65fa 100644 --- a/data/station/ALJ.json +++ b/data/station/ALJ.json @@ -61,5 +61,56 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "ALJ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue" + ], + "paidArea": false + }, + { + "id": "ALJ_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "ALJ_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "ALJ_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/AMK.json b/data/station/AMK.json index dc898b9f..86e496d7 100644 --- a/data/station/AMK.json +++ b/data/station/AMK.json @@ -69,5 +69,106 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "AMK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Ang Mo Kio Avenue 8" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "AMK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Ang Mo Kio Avenue 8" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "AMK_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Ang Mo Kio Avenue 8" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "AMK_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "operationalStatus": "temporarily_closed", + "roadNames": [ + "Ang Mo Kio Avenue 8" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "AMK_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "AMK_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "AMK_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "AMK_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BAK.json b/data/station/BAK.json index 4f9c5f1f..640b1393 100644 --- a/data/station/BAK.json +++ b/data/station/BAK.json @@ -24,5 +24,51 @@ "sengkang-sports-complex", "sengkang-grand-mall" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "BAK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BAK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BAK_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "BAK_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/BBS.json b/data/station/BBS.json index 681dbc4e..064b666e 100644 --- a/data/station/BBS.json +++ b/data/station/BBS.json @@ -62,5 +62,77 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BBS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BBS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BBS_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BBS_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BBS_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BBS_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CBBS_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CBBS_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BBT.json b/data/station/BBT.json index 5dba5735..be90325d 100644 --- a/data/station/BBT.json +++ b/data/station/BBT.json @@ -61,5 +61,68 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BBT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "BBT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BBT_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BBT_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BBT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BBT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BCL.json b/data/station/BCL.json index 22c8a6a9..a0105c54 100644 --- a/data/station/BCL.json +++ b/data/station/BCL.json @@ -62,5 +62,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BCL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BCL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BCL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BCL_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BCL_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BDK.json b/data/station/BDK.json index 78b3fca1..11660cbd 100644 --- a/data/station/BDK.json +++ b/data/station/BDK.json @@ -62,5 +62,71 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BDK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "New Upper Changi Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BDK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "New Upper Changi Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BDK_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "New Upper Changi Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BDK_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BDK_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BDL.json b/data/station/BDL.json index 636f3d1b..eb8fa576 100644 --- a/data/station/BDL.json +++ b/data/station/BDL.json @@ -62,5 +62,68 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BDL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Lorong 1 Toa Payoh" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BDL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Lorong 1 Toa Payoh" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BDL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Lorong 1 Toa Payoh" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "BDL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BDL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BDM.json b/data/station/BDM.json index f4dfa202..aeb24340 100644 --- a/data/station/BDM.json +++ b/data/station/BDM.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BDM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BDM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BDM_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BDM_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BDN.json b/data/station/BDN.json index 56282dd7..b1f5e1db 100644 --- a/data/station/BDN.json +++ b/data/station/BDN.json @@ -62,5 +62,65 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BDN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BDN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BDN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BDN_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BDN_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BDR.json b/data/station/BDR.json index 18702472..58bd4664 100644 --- a/data/station/BDR.json +++ b/data/station/BDR.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BDR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BDR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BDR_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BDR_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BFT.json b/data/station/BFT.json index 007dd51f..c4be6362 100644 --- a/data/station/BFT.json +++ b/data/station/BFT.json @@ -110,5 +110,187 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BFT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BFT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BFT_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BFT_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BFT_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BFT_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BFT_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BFT_DTL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BFT_CCL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BFT_XFER_A_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BFT_DTL_A" + }, + "to": { + "kind": "platform", + "id": "BFT_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BFT_XFER_C_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BFT_DTL_C" + }, + "to": { + "kind": "platform", + "id": "BFT_CCL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BFT_XFER_DTL_A_CCL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BFT_DTL_A" + }, + "to": { + "kind": "platform", + "id": "BFT_CCL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BFT_XFER_CCL_B_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BFT_CCL_B" + }, + "to": { + "kind": "platform", + "id": "BFT_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BGB.json b/data/station/BGB.json index 3963fc5f..541e1e3b 100644 --- a/data/station/BGB.json +++ b/data/station/BGB.json @@ -62,5 +62,65 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BGB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BGB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BGB_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BGB_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BGB_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BGB_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BGK.json b/data/station/BGK.json index e49491ff..5ee5fc22 100644 --- a/data/station/BGK.json +++ b/data/station/BGK.json @@ -61,5 +61,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BGK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BGK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BGK_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BGK_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BGS.json b/data/station/BGS.json index 205af782..1068832b 100644 --- a/data/station/BGS.json +++ b/data/station/BGS.json @@ -106,5 +106,183 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BGS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BGS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BGS_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BGS_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BGS_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BGS_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BGS_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BGS_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BGS_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BGS_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BGS_XFER_EWL_A_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BGS_EWL_A" + }, + "to": { + "kind": "platform", + "id": "BGS_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BGS_XFER_EWL_A_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BGS_EWL_A" + }, + "to": { + "kind": "platform", + "id": "BGS_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BGS_XFER_EWL_B_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BGS_EWL_B" + }, + "to": { + "kind": "platform", + "id": "BGS_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BGS_XFER_EWL_B_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BGS_EWL_B" + }, + "to": { + "kind": "platform", + "id": "BGS_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BKP.json b/data/station/BKP.json index d12f5ce2..2a55b61b 100644 --- a/data/station/BKP.json +++ b/data/station/BKP.json @@ -85,5 +85,200 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BKP_EXIT_A1", + "label": "A1", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Upper Bukit Timah Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BKP_EXIT_A2", + "label": "A2", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Upper Bukit Timah Road" + ], + "paidArea": false + }, + { + "id": "BKP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Upper Bukit Timah Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BKP_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Bukit Panjang Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BKP_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BKP_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 1, + "BPLRT_B": 1 + }, + "accessPoints": [] + }, + { + "id": "BKP_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + }, + { + "id": "BKP_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BKP_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BKP_XFER_BPLRT_1_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BKP_BPLRT_1" + }, + "to": { + "kind": "platform", + "id": "BKP_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BKP_XFER_BPLRT_1_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BKP_BPLRT_1" + }, + "to": { + "kind": "platform", + "id": "BKP_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BKP_XFER_BPLRT_2_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BKP_BPLRT_2" + }, + "to": { + "kind": "platform", + "id": "BKP_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BKP_XFER_BPLRT_2_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BKP_BPLRT_2" + }, + "to": { + "kind": "platform", + "id": "BKP_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BKT.json b/data/station/BKT.json index 10036972..b40c1b3c 100644 --- a/data/station/BKT.json +++ b/data/station/BKT.json @@ -61,5 +61,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BKT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BKT_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "BKT_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BLY.json b/data/station/BLY.json index 256fab61..68a62662 100644 --- a/data/station/BLY.json +++ b/data/station/BLY.json @@ -61,5 +61,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BLY_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Bartley Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BLY_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Bartley Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CBLY_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CBLY_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BNK.json b/data/station/BNK.json index 9899051f..75a046b0 100644 --- a/data/station/BNK.json +++ b/data/station/BNK.json @@ -61,5 +61,63 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BNK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BNK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "BNK_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + } + ], + "platforms": [ + { + "id": "BNK_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BNK_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BNL.json b/data/station/BNL.json index c333e8da..c74ceeb6 100644 --- a/data/station/BNL.json +++ b/data/station/BNL.json @@ -69,5 +69,77 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BNL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BNL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BNL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BNL_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "BNL_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BNL_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BNL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BNL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BNV.json b/data/station/BNV.json index 82cdb021..50bcb0cc 100644 --- a/data/station/BNV.json +++ b/data/station/BNV.json @@ -103,5 +103,173 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BNV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BNV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "BNV_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BNV_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BNV_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BNV_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BNV_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BNV_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BNV_XFER_EWL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BNV_EWL_A" + }, + "to": { + "kind": "platform", + "id": "BNV_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BNV_XFER_EWL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BNV_EWL_A" + }, + "to": { + "kind": "platform", + "id": "BNV_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BNV_XFER_EWL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BNV_EWL_B" + }, + "to": { + "kind": "platform", + "id": "BNV_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BNV_XFER_EWL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BNV_EWL_B" + }, + "to": { + "kind": "platform", + "id": "BNV_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BRH.json b/data/station/BRH.json index a9a1858b..9c5fd5c8 100644 --- a/data/station/BRH.json +++ b/data/station/BRH.json @@ -68,5 +68,71 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BRH_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BRH_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BRH_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BRH_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TBRH_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TBRH_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BSH.json b/data/station/BSH.json index 5508eba6..f1c464d9 100644 --- a/data/station/BSH.json +++ b/data/station/BSH.json @@ -103,5 +103,182 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BSH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSH_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSH_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSH_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "BSH_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BSH_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "BSH_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BSH_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BSH_XFER_NSL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BSH_NSL_A" + }, + "to": { + "kind": "platform", + "id": "BSH_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BSH_XFER_NSL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BSH_NSL_A" + }, + "to": { + "kind": "platform", + "id": "BSH_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BSH_XFER_NSL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BSH_NSL_B" + }, + "to": { + "kind": "platform", + "id": "BSH_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BSH_XFER_NSL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BSH_NSL_B" + }, + "to": { + "kind": "platform", + "id": "BSH_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BSR.json b/data/station/BSR.json index 2874c076..0b934493 100644 --- a/data/station/BSR.json +++ b/data/station/BSR.json @@ -44,5 +44,79 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BSR_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSR_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSR_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSR_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BSR_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "BSR_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "boardingStatus": "alighting_only", + "lineId": "TEL", + "serviceIds": [], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "BSR_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/BTN.json b/data/station/BTN.json index 72691671..98e05320 100644 --- a/data/station/BTN.json +++ b/data/station/BTN.json @@ -103,5 +103,159 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BTN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "BTN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BTN_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BTN_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BTN_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BTN_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "BTN_XFER_CCL_A_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BTN_CCL_A" + }, + "to": { + "kind": "platform", + "id": "BTN_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BTN_XFER_CCL_A_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BTN_CCL_A" + }, + "to": { + "kind": "platform", + "id": "BTN_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BTN_XFER_CCL_B_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BTN_CCL_B" + }, + "to": { + "kind": "platform", + "id": "BTN_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "BTN_XFER_CCL_B_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "BTN_CCL_B" + }, + "to": { + "kind": "platform", + "id": "BTN_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/BTW.json b/data/station/BTW.json index 239aa88e..ab525d99 100644 --- a/data/station/BTW.json +++ b/data/station/BTW.json @@ -61,5 +61,65 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "BTW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BTW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "BTW_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "BTW_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "BTW_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CBR.json b/data/station/CBR.json index 89a1cd01..201b4cf9 100644 --- a/data/station/CBR.json +++ b/data/station/CBR.json @@ -62,5 +62,71 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CBR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CBR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CBR_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CBR_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CBR_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CBR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CBR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CCK.json b/data/station/CCK.json index bb5fa488..f95f34af 100644 --- a/data/station/CCK.json +++ b/data/station/CCK.json @@ -110,5 +110,275 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CCK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CCK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CCK_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CCK_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "operationalStatus": "temporarily_closed", + "paidArea": false + }, + { + "id": "CCK_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CCK_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CCK_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CCK_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + }, + { + "id": "CCK_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + }, + { + "id": "CCK_BPLRT_3", + "label": "3", + "lastUpdated": "2026-07-18", + "boardingStatus": "alighting_only", + "lineId": "BPLRT", + "serviceIds": [], + "accessPoints": [] + }, + { + "id": "CCK_BPLRT_4", + "label": "4", + "lastUpdated": "2026-07-18", + "boardingStatus": "alighting_only", + "lineId": "BPLRT", + "serviceIds": [], + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "CCK_XFER_NSL_A_BPLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCK_NSL_A" + }, + "to": { + "kind": "platform", + "id": "CCK_BPLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_NSL_A_BPLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCK_NSL_A" + }, + "to": { + "kind": "platform", + "id": "CCK_BPLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_NSL_B_BPLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCK_NSL_B" + }, + "to": { + "kind": "platform", + "id": "CCK_BPLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_NSL_B_BPLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCK_NSL_B" + }, + "to": { + "kind": "platform", + "id": "CCK_BPLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_BPLRT_3_NSL_A", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "CCK_BPLRT_3" + }, + "to": { + "kind": "platform", + "id": "CCK_NSL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_BPLRT_3_NSL_B", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "CCK_BPLRT_3" + }, + "to": { + "kind": "platform", + "id": "CCK_NSL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_BPLRT_4_NSL_A", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "CCK_BPLRT_4" + }, + "to": { + "kind": "platform", + "id": "CCK_NSL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CCK_XFER_BPLRT_4_NSL_B", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "CCK_BPLRT_4" + }, + "to": { + "kind": "platform", + "id": "CCK_NSL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/CDT.json b/data/station/CDT.json index b222b690..fb2ee548 100644 --- a/data/station/CDT.json +++ b/data/station/CDT.json @@ -105,47 +105,185 @@ }, "layout": { "levels": [], - "exits": [], + "exits": [ + { + "id": "CDT_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Toa Payoh Rise" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CDT_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Toa Payoh Rise" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CDT_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Toa Payoh Rise" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CDT_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Toa Payoh Link" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], "platforms": [ { "id": "CCDT_A", "label": "A", + "lastUpdated": "2026-07-18", "lineId": "CCL", "serviceIds": [ "CCL_BRANCH_CCW", "CCL_LOOP_CCW" ], + "doorCount": 12, "accessPoints": [] }, { "id": "CCDT_B", "label": "B", + "lastUpdated": "2026-07-18", "lineId": "CCL", "serviceIds": [ "CCL_BRANCH_CW", "CCL_LOOP_CW" ], + "doorCount": 12, "accessPoints": [] }, { "id": "TCDT_D", "label": "D", + "lastUpdated": "2026-07-18", "lineId": "TEL", "serviceIds": [ "TEL_MAIN_N" ], + "doorCount": 20, "accessPoints": [] }, { "id": "TCDT_C", "label": "C", + "lastUpdated": "2026-07-18", "lineId": "TEL", "serviceIds": [ "TEL_MAIN_S" ], + "doorCount": 20, "accessPoints": [] } ], - "transferPaths": [] + "transferPaths": [ + { + "id": "CDT_XFER_CCL_A_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCDT_A" + }, + "to": { + "kind": "platform", + "id": "TCDT_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CDT_XFER_CCL_A_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCDT_A" + }, + "to": { + "kind": "platform", + "id": "TCDT_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CDT_XFER_CCL_B_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCDT_B" + }, + "to": { + "kind": "platform", + "id": "TCDT_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CDT_XFER_CCL_B_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CCDT_B" + }, + "to": { + "kind": "platform", + "id": "TCDT_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/CGA.json b/data/station/CGA.json index 8d131d35..1628a743 100644 --- a/data/station/CGA.json +++ b/data/station/CGA.json @@ -52,5 +52,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CGA_EXIT_TERMINAL_2", + "label": "Terminal 2", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CGA_EXIT_TERMINAL_2_3", + "label": "Terminal 2/3", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CGA_EXIT_TERMINAL_3", + "label": "Terminal 3", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CGA_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CGA_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CGL.json b/data/station/CGL.json index b00b366b..724c1081 100644 --- a/data/station/CGL.json +++ b/data/station/CGL.json @@ -24,5 +24,45 @@ "compass-one", "sengkang-sports-complex" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "CGL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CGL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CGL_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "CGL_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/CLE.json b/data/station/CLE.json index 9c95b938..799f3689 100644 --- a/data/station/CLE.json +++ b/data/station/CLE.json @@ -69,5 +69,83 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CLE_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CLE_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CLE_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CLE_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CLE_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CLE_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CNG.json b/data/station/CNG.json index 98d4c003..ea04cfdf 100644 --- a/data/station/CNG.json +++ b/data/station/CNG.json @@ -62,5 +62,68 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CNG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Boon Lay Way" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CNG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Boon Lay Way" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CNG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Boon Lay Way" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "CNG_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CNG_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/COM.json b/data/station/COM.json index 2959c331..e728dc65 100644 --- a/data/station/COM.json +++ b/data/station/COM.json @@ -61,5 +61,83 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "COM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "COM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "COM_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "COM_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "COM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "COM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/COV.json b/data/station/COV.json index 8632fd0b..2776cb4a 100644 --- a/data/station/COV.json +++ b/data/station/COV.json @@ -23,5 +23,45 @@ "punggol-waterway-park", "oasis-terraces" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "COV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "COV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "COV_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "COV_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/CPV.json b/data/station/CPV.json index dfdfe1eb..21c95e66 100644 --- a/data/station/CPV.json +++ b/data/station/CPV.json @@ -24,5 +24,51 @@ "sengkang-riverside-park", "sengkang-general-hospital" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "CPV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CPV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CPV_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "CPV_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/CRE.json b/data/station/CRE.json index 2dd18aa0..1c13422a 100644 --- a/data/station/CRE.json +++ b/data/station/CRE.json @@ -23,5 +23,45 @@ "coral-edge-community-centre", "punggol-waterway-park" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "CRE_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CRE_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CRE_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "CRE_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/CRQ.json b/data/station/CRQ.json index c154bed3..218cf34d 100644 --- a/data/station/CRQ.json +++ b/data/station/CRQ.json @@ -62,5 +62,78 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CRQ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CRQ_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "CRQ_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CRQ_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "CRQ_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CRQ_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CRQ_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CRQ_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CSW.json b/data/station/CSW.json index e2450aad..9267c12d 100644 --- a/data/station/CSW.json +++ b/data/station/CSW.json @@ -62,5 +62,45 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CSW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "CSW_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CSW_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/CTH.json b/data/station/CTH.json index 0c037ae1..caa47ed6 100644 --- a/data/station/CTH.json +++ b/data/station/CTH.json @@ -104,5 +104,168 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CTH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CTH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "CTH_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CTH_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CTH_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CTH_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CTH_NSL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CTH_EWL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "CTH_XFER_A_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTH_NSL_A" + }, + "to": { + "kind": "platform", + "id": "CTH_EWL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTH_XFER_C_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTH_NSL_C" + }, + "to": { + "kind": "platform", + "id": "CTH_EWL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTH_XFER_NSL_A_EWL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTH_NSL_A" + }, + "to": { + "kind": "platform", + "id": "CTH_EWL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTH_XFER_EWL_B_NSL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTH_EWL_B" + }, + "to": { + "kind": "platform", + "id": "CTH_NSL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/CTM.json b/data/station/CTM.json index ba6cc8d2..367b9208 100644 --- a/data/station/CTM.json +++ b/data/station/CTM.json @@ -24,5 +24,61 @@ "public-transport-security-command", "cantonment-police-complex" ], - "townId": "outram" + "townId": "outram", + "layout": { + "levels": [], + "exits": [ + { + "id": "CTM_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CTM_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CTM_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "CTM_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CTM_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CTM_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/CTN.json b/data/station/CTN.json index 638ef0ae..56583281 100644 --- a/data/station/CTN.json +++ b/data/station/CTN.json @@ -108,5 +108,182 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "CTN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CTN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "CTN_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CTN_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "CTN_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "CTN_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CTN_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CTN_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "CTN_DTL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CTN_DTL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "CTN_XFER_NEL_A_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTN_NEL_A" + }, + "to": { + "kind": "platform", + "id": "CTN_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTN_XFER_NEL_A_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTN_NEL_A" + }, + "to": { + "kind": "platform", + "id": "CTN_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTN_XFER_NEL_B_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTN_NEL_B" + }, + "to": { + "kind": "platform", + "id": "CTN_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "CTN_XFER_NEL_B_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "CTN_NEL_B" + }, + "to": { + "kind": "platform", + "id": "CTN_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/DAM.json b/data/station/DAM.json index eff596e8..93128e97 100644 --- a/data/station/DAM.json +++ b/data/station/DAM.json @@ -24,5 +24,45 @@ "punggol-plaza", "waterway-point" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "DAM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DAM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "DAM_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "DAM_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/DBG.json b/data/station/DBG.json index f661b64b..f01b0bd2 100644 --- a/data/station/DBG.json +++ b/data/station/DBG.json @@ -128,5 +128,364 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "DBG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DBG_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + } + ], + "platforms": [ + { + "id": "DBG_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "DBG_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "DBG_CCL_A", + "label": "A", + "lastUpdated": "2026-07-19", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "DBG_CCL_B", + "label": "B", + "lastUpdated": "2026-07-19", + "boardingStatus": "alighting_only", + "lineId": "CCL", + "serviceIds": [], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "DBG_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "DBG_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "DBG_XFER_NSL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_A_NEL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_A_NEL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_B_NEL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_NSL_B_NEL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_NSL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_CCL_A_NEL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_CCL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_CCL_A_NEL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_CCL_A" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_CCL_B_NEL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_CCL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "DBG_XFER_CCL_B_NEL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "DBG_CCL_B" + }, + "to": { + "kind": "platform", + "id": "DBG_NEL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/DKT.json b/data/station/DKT.json index 70551f0b..08f3a531 100644 --- a/data/station/DKT.json +++ b/data/station/DKT.json @@ -62,5 +62,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "DKT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Old Airport Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "DKT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Old Airport Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CDKT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CDKT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/DTN.json b/data/station/DTN.json index 79c966f3..f22c4f23 100644 --- a/data/station/DTN.json +++ b/data/station/DTN.json @@ -62,5 +62,78 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "DTN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DTN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "DTN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DTN_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "DTN_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "DTN_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "DTN_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "DTN_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/DVR.json b/data/station/DVR.json index 94957e64..9131ce5e 100644 --- a/data/station/DVR.json +++ b/data/station/DVR.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "DVR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "DVR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Commonwealth Avenue West" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "DVR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "DVR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/EPN.json b/data/station/EPN.json index c4734621..c6afb95d 100644 --- a/data/station/EPN.json +++ b/data/station/EPN.json @@ -62,5 +62,86 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "EPN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "EPN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "EPN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "EPN_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "EPN_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "EPN_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "EPN_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CEPN_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CEPN_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/EUN.json b/data/station/EUN.json index f0813bd6..7da66fde 100644 --- a/data/station/EUN.json +++ b/data/station/EUN.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "EUN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "EUN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "EUN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "EUN_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "EUN_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/FCN.json b/data/station/FCN.json index 13a6c1d6..01863223 100644 --- a/data/station/FCN.json +++ b/data/station/FCN.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "FCN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "FCN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "FCN_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "FCN_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/FJR.json b/data/station/FJR.json index 0cba3467..236592b0 100644 --- a/data/station/FJR.json +++ b/data/station/FJR.json @@ -61,5 +61,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "FJR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "FJR_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "FJR_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/FMW.json b/data/station/FMW.json index 57f3f79e..a907a8e5 100644 --- a/data/station/FMW.json +++ b/data/station/FMW.json @@ -24,5 +24,51 @@ "anchorvale-community-club", "sengkang-sports-centre" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "FMW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "FMW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "FMW_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "FMW_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/FNV.json b/data/station/FNV.json index fd8fda84..d8330edf 100644 --- a/data/station/FNV.json +++ b/data/station/FNV.json @@ -24,5 +24,45 @@ "compass-one", "fernvale-point" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "FNV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FNV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "FNV_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "FNV_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/FRP.json b/data/station/FRP.json index a48ed501..c76cb81d 100644 --- a/data/station/FRP.json +++ b/data/station/FRP.json @@ -62,5 +62,95 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "FRP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "FRP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "FRP_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_H", + "label": "H", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "FRP_EXIT_I", + "label": "I", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "FRP_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "FRP_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/FRR.json b/data/station/FRR.json index e9f30587..ec805ee9 100644 --- a/data/station/FRR.json +++ b/data/station/FRR.json @@ -60,5 +60,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "FRR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Farrer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "FRR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Farrer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CFRR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CFRR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/GCL.json b/data/station/GCL.json index bd66ec77..300724a2 100644 --- a/data/station/GCL.json +++ b/data/station/GCL.json @@ -65,5 +65,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "GCL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GCL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "GCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "GCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/GLB.json b/data/station/GLB.json index 92eff089..208d3c5f 100644 --- a/data/station/GLB.json +++ b/data/station/GLB.json @@ -61,5 +61,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "GLB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "GLB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "GLB_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "GLB_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/GRB.json b/data/station/GRB.json index c4b4fa8d..5f07f7c5 100644 --- a/data/station/GRB.json +++ b/data/station/GRB.json @@ -62,5 +62,62 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "GRB_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRB_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRB_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "GRB_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "GRB_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/GRW.json b/data/station/GRW.json index 4af8e93c..b97810e2 100644 --- a/data/station/GRW.json +++ b/data/station/GRW.json @@ -61,5 +61,86 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "GRW_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRW_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "GRW_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRW_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRW_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "GRW_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TGRW_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TGRW_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HBF.json b/data/station/HBF.json index bfbe359d..469ca23b 100644 --- a/data/station/HBF.json +++ b/data/station/HBF.json @@ -69,5 +69,188 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HBF_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "HBF_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "HBF_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "HBF_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "HBF_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "HBF_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "HBF_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "HBF_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "serviceStopOccurrences": { + "CCL_LOOP_CCW": 0 + }, + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "HBF_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "serviceStopOccurrences": { + "CCL_LOOP_CW": 0 + }, + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "HBF_XFER_NEL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "HBF_NEL_A" + }, + "to": { + "kind": "platform", + "id": "HBF_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "HBF_XFER_NEL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "HBF_NEL_A" + }, + "to": { + "kind": "platform", + "id": "HBF_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "HBF_XFER_NEL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "HBF_NEL_B" + }, + "to": { + "kind": "platform", + "id": "HBF_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "HBF_XFER_NEL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "HBF_NEL_B" + }, + "to": { + "kind": "platform", + "id": "HBF_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/HGN.json b/data/station/HGN.json index 97a6e56f..34ddf3af 100644 --- a/data/station/HGN.json +++ b/data/station/HGN.json @@ -69,5 +69,60 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HGN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "HGN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "HGN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "HGN_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "HGN_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HLV.json b/data/station/HLV.json index 23a6863a..8960f66f 100644 --- a/data/station/HLV.json +++ b/data/station/HLV.json @@ -62,5 +62,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HLV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "HLV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "HLV_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CHLV_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CHLV_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HME.json b/data/station/HME.json index b399f33e..be344a28 100644 --- a/data/station/HME.json +++ b/data/station/HME.json @@ -60,5 +60,47 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HME_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "HME_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "HME_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "HME_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HPV.json b/data/station/HPV.json index 21dbb8e8..d35add14 100644 --- a/data/station/HPV.json +++ b/data/station/HPV.json @@ -60,5 +60,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HPV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "West Coast Highway" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CHPV_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CHPV_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HVL.json b/data/station/HVL.json index 20541a7a..fdc534a1 100644 --- a/data/station/HVL.json +++ b/data/station/HVL.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HVL_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "HVL_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "HVL_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "HVL_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "HVL_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "THVL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "THVL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/HVW.json b/data/station/HVW.json index 5214ac37..8d4fb1d0 100644 --- a/data/station/HVW.json +++ b/data/station/HVW.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "HVW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "HVW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "HVW_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "HVW_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/JKN.json b/data/station/JKN.json index 9e757276..277e6f44 100644 --- a/data/station/JKN.json +++ b/data/station/JKN.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "JKN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "JKN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "JKN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "JKN_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JKN_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/JLB.json b/data/station/JLB.json index b6e3f396..167b5b61 100644 --- a/data/station/JLB.json +++ b/data/station/JLB.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "JLB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "JLB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "JLB_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "JLB_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/JLP.json b/data/station/JLP.json index 3baaabaf..81a4f20b 100644 --- a/data/station/JLP.json +++ b/data/station/JLP.json @@ -62,5 +62,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "JLP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "JLP_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "JLP_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/JUR.json b/data/station/JUR.json index 096d48fb..422352dd 100644 --- a/data/station/JUR.json +++ b/data/station/JUR.json @@ -93,5 +93,296 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "JUR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "JUR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "JUR_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "JUR_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "JUR_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JUR_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JUR_EWL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JUR_NSL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JUR_NSL_E", + "label": "E", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "JUR_EWL_F", + "label": "F", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "JUR_XFER_A_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_NSL_A" + }, + "to": { + "kind": "platform", + "id": "JUR_EWL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_C_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_EWL_C" + }, + "to": { + "kind": "platform", + "id": "JUR_NSL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_E_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_NSL_E" + }, + "to": { + "kind": "platform", + "id": "JUR_EWL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_NSL_A_EWL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_NSL_A" + }, + "to": { + "kind": "platform", + "id": "JUR_EWL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_NSL_A_EWL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_NSL_A" + }, + "to": { + "kind": "platform", + "id": "JUR_EWL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_EWL_B_NSL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_EWL_B" + }, + "to": { + "kind": "platform", + "id": "JUR_NSL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_EWL_B_NSL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_EWL_B" + }, + "to": { + "kind": "platform", + "id": "JUR_NSL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_EWL_C_NSL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_EWL_C" + }, + "to": { + "kind": "platform", + "id": "JUR_NSL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "JUR_XFER_NSL_D_EWL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "JUR_NSL_D" + }, + "to": { + "kind": "platform", + "id": "JUR_EWL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/KAL.json b/data/station/KAL.json index 91d1c3ce..90ace1b9 100644 --- a/data/station/KAL.json +++ b/data/station/KAL.json @@ -62,5 +62,56 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KAL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue" + ], + "paidArea": false + }, + { + "id": "KAL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "KAL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "KAL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KAP.json b/data/station/KAP.json index 03df602e..846c466a 100644 --- a/data/station/KAP.json +++ b/data/station/KAP.json @@ -68,5 +68,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KAP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "KAP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "KAP_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "KAP_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KDL.json b/data/station/KDL.json index d1d8bb7c..1e99a949 100644 --- a/data/station/KDL.json +++ b/data/station/KDL.json @@ -24,5 +24,45 @@ "punggol-waterway-park", "punggol-town-hub" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "KDL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "KDL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "KDL_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "KDL_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/KEM.json b/data/station/KEM.json index 7273fb45..93f080a2 100644 --- a/data/station/KEM.json +++ b/data/station/KEM.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KEM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue East" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KEM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sims Avenue East" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "KEM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "KEM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KGK.json b/data/station/KGK.json index 18c7151c..91b4ead0 100644 --- a/data/station/KGK.json +++ b/data/station/KGK.json @@ -24,5 +24,51 @@ "compass-one", "sengkang-riverside-park" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "KGK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KGK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "KGK_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "KGK_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/KKB.json b/data/station/KKB.json index 0768a241..fce76f8d 100644 --- a/data/station/KKB.json +++ b/data/station/KKB.json @@ -60,5 +60,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KKB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "KKB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "KKB_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "KKB_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KPG.json b/data/station/KPG.json index e654a925..6f178b74 100644 --- a/data/station/KPG.json +++ b/data/station/KPG.json @@ -24,5 +24,53 @@ "sengkang-general-hospital", "sengkang-sports-centre" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "KPG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "KPG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "KPG_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "KPG_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/KPL.json b/data/station/KPL.json index 4ed1115b..84700845 100644 --- a/data/station/KPL.json +++ b/data/station/KPL.json @@ -24,5 +24,49 @@ "harbourfront-centre", "sentosa-gateway" ], - "townId": "bukit-merah" + "townId": "bukit-merah", + "layout": { + "levels": [], + "exits": [ + { + "id": "KPL_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "KPL_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "KPL_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "KPL_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/KRG.json b/data/station/KRG.json index 3bca1066..c925aab7 100644 --- a/data/station/KRG.json +++ b/data/station/KRG.json @@ -62,5 +62,70 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KRG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KRG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "KRG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KRG_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CKRG_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CKRG_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KRJ.json b/data/station/KRJ.json index 5b3f833a..7df87fe8 100644 --- a/data/station/KRJ.json +++ b/data/station/KRJ.json @@ -62,5 +62,68 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KRJ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KRJ_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KRJ_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KRJ_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "KRJ_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "KRJ_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KTB.json b/data/station/KTB.json index e16360f7..4a5b3cb2 100644 --- a/data/station/KTB.json +++ b/data/station/KTB.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KTB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KTB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "KTB_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false + }, + { + "id": "KTB_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "KTB_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "KTB_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KTH.json b/data/station/KTH.json index cafd21ff..d57b1f3d 100644 --- a/data/station/KTH.json +++ b/data/station/KTH.json @@ -60,5 +60,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KTH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "KTH_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 1, + "BPLRT_B": 1 + }, + "accessPoints": [] + }, + { + "id": "KTH_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KTP.json b/data/station/KTP.json index fbd656f8..574b455e 100644 --- a/data/station/KTP.json +++ b/data/station/KTP.json @@ -62,5 +62,47 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KTP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "KTP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "KTP_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "KTP_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/KVN.json b/data/station/KVN.json index 104a3783..136d560c 100644 --- a/data/station/KVN.json +++ b/data/station/KVN.json @@ -61,5 +61,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "KVN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "KVN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "KVN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "KVN_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "KVN_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LBD.json b/data/station/LBD.json index 0182b005..e7a0ce6f 100644 --- a/data/station/LBD.json +++ b/data/station/LBD.json @@ -62,5 +62,46 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LBD_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CLBD_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CLBD_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LKS.json b/data/station/LKS.json index 1d0f5e9e..2b224ae0 100644 --- a/data/station/LKS.json +++ b/data/station/LKS.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LKS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LKS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "LKS_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "LKS_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "LKS_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LRC.json b/data/station/LRC.json index 397219a8..f05fa4dc 100644 --- a/data/station/LRC.json +++ b/data/station/LRC.json @@ -61,5 +61,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LRC_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LRC_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CLRC_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CLRC_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LTI.json b/data/station/LTI.json index 71051874..7be69b26 100644 --- a/data/station/LTI.json +++ b/data/station/LTI.json @@ -103,5 +103,190 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LTI_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "LTI_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "LTI_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "LTI_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "LTI_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "LTI_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "LTI_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "LTI_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "LTI_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "LTI_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "LTI_XFER_NEL_A_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "LTI_NEL_A" + }, + "to": { + "kind": "platform", + "id": "LTI_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "LTI_XFER_NEL_A_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "LTI_NEL_A" + }, + "to": { + "kind": "platform", + "id": "LTI_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "LTI_XFER_NEL_B_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "LTI_NEL_B" + }, + "to": { + "kind": "platform", + "id": "LTI_DTL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "LTI_XFER_NEL_B_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "LTI_NEL_B" + }, + "to": { + "kind": "platform", + "id": "LTI_DTL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/LTR.json b/data/station/LTR.json index 6501162b..f8a53086 100644 --- a/data/station/LTR.json +++ b/data/station/LTR.json @@ -60,5 +60,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LTR_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LTR_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LTR_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LTR_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LTR_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TLTR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TLTR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LVR.json b/data/station/LVR.json index 41cacd28..eb855d24 100644 --- a/data/station/LVR.json +++ b/data/station/LVR.json @@ -60,5 +60,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "LVR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Kallang Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LVR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Kallang Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "LVR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "LVR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/LYR.json b/data/station/LYR.json index 9389c43c..00d05fa7 100644 --- a/data/station/LYR.json +++ b/data/station/LYR.json @@ -24,5 +24,51 @@ "the-rivervale-mall", "sengkang-community-hospital" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "LYR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "LYR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "LYR_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "LYR_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/MAX.json b/data/station/MAX.json index 24e84397..bad1f065 100644 --- a/data/station/MAX.json +++ b/data/station/MAX.json @@ -62,5 +62,62 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MAX_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MAX_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MAX_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TMAX_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TMAX_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MBT.json b/data/station/MBT.json index f28ce96b..468d98e5 100644 --- a/data/station/MBT.json +++ b/data/station/MBT.json @@ -62,5 +62,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MBT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Old Airport Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MBT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Old Airport Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CMBT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CMBT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MFL.json b/data/station/MFL.json index 07548312..c4ea49cb 100644 --- a/data/station/MFL.json +++ b/data/station/MFL.json @@ -61,5 +61,98 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MFL_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MFL_EXIT_7", + "label": "7", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TMFL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TMFL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MPR.json b/data/station/MPR.json index ba1e8f67..1c66dacb 100644 --- a/data/station/MPR.json +++ b/data/station/MPR.json @@ -62,5 +62,82 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MPR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "roadNames": [ + "Marine Parade Road" + ], + "paidArea": false + }, + { + "id": "MPR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "roadNames": [ + "Marine Parade Road" + ], + "paidArea": false + }, + { + "id": "MPR_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-19", + "roadNames": [ + "Joo Chiat Road", + "Marine Parade Road" + ], + "paidArea": false + }, + { + "id": "MPR_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-19", + "roadNames": [ + "Marine Parade Road" + ], + "paidArea": false + }, + { + "id": "MPR_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-19", + "roadNames": [ + "Marine Parade Road", + "Still Road South" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "MPR_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "MPR_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MPS.json b/data/station/MPS.json index 2db6a6a6..e7887b86 100644 --- a/data/station/MPS.json +++ b/data/station/MPS.json @@ -102,5 +102,186 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MPS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "MPS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "MPS_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "MPS_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "MPS_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "MPS_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MPS_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MPS_DTL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MPS_DTL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "MPS_XFER_CCL_A_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MPS_CCL_A" + }, + "to": { + "kind": "platform", + "id": "MPS_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MPS_XFER_CCL_A_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MPS_CCL_A" + }, + "to": { + "kind": "platform", + "id": "MPS_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MPS_XFER_CCL_B_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MPS_CCL_B" + }, + "to": { + "kind": "platform", + "id": "MPS_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MPS_XFER_CCL_B_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MPS_CCL_B" + }, + "to": { + "kind": "platform", + "id": "MPS_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/MRB.json b/data/station/MRB.json index 4cc3a0ed..f2bd1537 100644 --- a/data/station/MRB.json +++ b/data/station/MRB.json @@ -134,5 +134,364 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MRB_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "MRB_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "MRB_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Bayfront Avenue", + "Park Street" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MRB_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-18", + "roadNames": [ + "Sheares Avenue" + ], + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "MRB_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "MRB_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "MRB_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "MRB_CCL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MRB_CCL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MRB_TEL_E", + "label": "E", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "MRB_TEL_F", + "label": "F", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "MRB_XFER_NSL_A_CCL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_A" + }, + "to": { + "kind": "platform", + "id": "MRB_CCL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_A_CCL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_A" + }, + "to": { + "kind": "platform", + "id": "MRB_CCL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_A_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_A" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_A_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_A" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_B_CCL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_B" + }, + "to": { + "kind": "platform", + "id": "MRB_CCL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_B_CCL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_B" + }, + "to": { + "kind": "platform", + "id": "MRB_CCL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_B_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_B" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_NSL_B_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_NSL_B" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_CCL_C_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_CCL_C" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_CCL_C_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_CCL_C" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_CCL_D_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_CCL_D" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "MRB_XFER_CCL_D_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "MRB_CCL_D" + }, + "to": { + "kind": "platform", + "id": "MRB_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/MRD.json b/data/station/MRD.json index ec6b5b7e..b9ecfc30 100644 --- a/data/station/MRD.json +++ b/data/station/MRD.json @@ -23,5 +23,45 @@ "punggol-waterway-park", "punggol-beach" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "MRD_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "MRD_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "MRD_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "MRD_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/MRM.json b/data/station/MRM.json index 4c953d1b..6c70fff1 100644 --- a/data/station/MRM.json +++ b/data/station/MRM.json @@ -62,5 +62,52 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MRM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MRM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CMRM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CMRM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MSL.json b/data/station/MSL.json index dfaf87b7..a9e3e6d7 100644 --- a/data/station/MSL.json +++ b/data/station/MSL.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MSL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 3" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MSL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 3" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MSL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 3" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MSL_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Woodlands Avenue 3" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "MSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "MSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MSP.json b/data/station/MSP.json index 35c9b590..773f2791 100644 --- a/data/station/MSP.json +++ b/data/station/MSP.json @@ -44,5 +44,58 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MSP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Marina Coastal Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "MSP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Marina Coastal Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "MSP_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "MSP_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "boardingStatus": "alighting_only", + "lineId": "NSL", + "serviceIds": [], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MTC.json b/data/station/MTC.json index f8e81012..8292fe27 100644 --- a/data/station/MTC.json +++ b/data/station/MTC.json @@ -62,5 +62,71 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MTC_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "MTC_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "MTC_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "MTC_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "MTC_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "MTC_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "MTC_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "MTC_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/MTR.json b/data/station/MTR.json index bba57493..be655ff8 100644 --- a/data/station/MTR.json +++ b/data/station/MTR.json @@ -61,5 +61,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "MTR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "MTR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "MTR_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "MTR_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/NBG.json b/data/station/NBG.json index b2871f68..c5637437 100644 --- a/data/station/NBG.json +++ b/data/station/NBG.json @@ -24,5 +24,45 @@ "waterway-point", "coney-island" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "NBG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "NBG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "NBG_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "NBG_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/NCH.json b/data/station/NCH.json index 4c9f5a17..74376514 100644 --- a/data/station/NCH.json +++ b/data/station/NCH.json @@ -96,5 +96,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "NCH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "NCH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CNCH_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CNCH_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/NEW.json b/data/station/NEW.json index 0de195b4..d7047268 100644 --- a/data/station/NEW.json +++ b/data/station/NEW.json @@ -103,5 +103,167 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "NEW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "NEW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "NEW_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "NEW_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "NEW_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "NEW_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "NEW_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "NEW_XFER_NSL_A_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "NEW_NSL_A" + }, + "to": { + "kind": "platform", + "id": "NEW_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "NEW_XFER_NSL_A_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "NEW_NSL_A" + }, + "to": { + "kind": "platform", + "id": "NEW_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "NEW_XFER_NSL_B_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "NEW_NSL_B" + }, + "to": { + "kind": "platform", + "id": "NEW_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "NEW_XFER_NSL_B_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "NEW_NSL_B" + }, + "to": { + "kind": "platform", + "id": "NEW_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/NOV.json b/data/station/NOV.json index 41b412ad..4318ba76 100644 --- a/data/station/NOV.json +++ b/data/station/NOV.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "NOV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "NOV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "NOV_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "NOV_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "NOV_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/NPR.json b/data/station/NPR.json index 23d1aa80..c0ed5963 100644 --- a/data/station/NPR.json +++ b/data/station/NPR.json @@ -62,5 +62,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "NPR_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "NPR_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TNPR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TNPR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/OAS.json b/data/station/OAS.json index 4b203ee2..e174051d 100644 --- a/data/station/OAS.json +++ b/data/station/OAS.json @@ -24,5 +24,45 @@ "punggol-waterway-park", "waterway-point" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "OAS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "OAS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "OAS_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "OAS_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/OBV.json b/data/station/OBV.json index 815180c3..de52e456 100644 --- a/data/station/OBV.json +++ b/data/station/OBV.json @@ -62,5 +62,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "OBV_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "OBV_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TOBV_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TOBV_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/ONH.json b/data/station/ONH.json index 038697f0..01c8972e 100644 --- a/data/station/ONH.json +++ b/data/station/ONH.json @@ -62,5 +62,67 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "ONH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "ONH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ONH_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ONH_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CONH_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CONH_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/ORC.json b/data/station/ORC.json index bb1ec825..ddaf1919 100644 --- a/data/station/ORC.json +++ b/data/station/ORC.json @@ -103,5 +103,237 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "ORC_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_7", + "label": "7", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_8", + "label": "8", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_9", + "label": "9", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "ORC_EXIT_10", + "label": "10", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_11", + "label": "11", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_12", + "label": "12", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "ORC_EXIT_13", + "label": "13", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "ORC_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "ORC_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "ORC_TEL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "ORC_TEL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "ORC_XFER_NSL_A_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "ORC_NSL_A" + }, + "to": { + "kind": "platform", + "id": "ORC_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "ORC_XFER_NSL_A_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "ORC_NSL_A" + }, + "to": { + "kind": "platform", + "id": "ORC_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "ORC_XFER_NSL_B_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "ORC_NSL_B" + }, + "to": { + "kind": "platform", + "id": "ORC_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "ORC_XFER_NSL_B_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "ORC_NSL_B" + }, + "to": { + "kind": "platform", + "id": "ORC_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/OTP.json b/data/station/OTP.json index 244ac493..38a68d1c 100644 --- a/data/station/OTP.json +++ b/data/station/OTP.json @@ -145,5 +145,380 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "OTP_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "OTP_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "OTP_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "OTP_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "OTP_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "OTP_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "OTP_EXIT_7", + "label": "7", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "OTP_EXIT_8", + "label": "8", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "OTP_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "OTP_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "OTP_NEL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "OTP_NEL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "OTP_TEL_E", + "label": "E", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "OTP_TEL_F", + "label": "F", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "OTP_XFER_EWL_A_NEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "OTP_NEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_A_NEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "OTP_NEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_A_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_A_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_B_NEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_B" + }, + "to": { + "kind": "platform", + "id": "OTP_NEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_B_NEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_B" + }, + "to": { + "kind": "platform", + "id": "OTP_NEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_B_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_B" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_EWL_B_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_EWL_B" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_NEL_C_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_NEL_C" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_NEL_C_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_NEL_C" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_NEL_D_TEL_E", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_NEL_D" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_E" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "OTP_XFER_NEL_D_TEL_F", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "OTP_NEL_D" + }, + "to": { + "kind": "platform", + "id": "OTP_TEL_F" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/PER.json b/data/station/PER.json index 0a9427f4..a72ddb99 100644 --- a/data/station/PER.json +++ b/data/station/PER.json @@ -25,5 +25,48 @@ "chinatown", "pearls-hill-city-park" ], - "townId": "downtown-core" + "townId": "downtown-core", + "layout": { + "levels": [], + "exits": [ + { + "id": "PER_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "PER_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PER_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PER_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/PGC.json b/data/station/PGC.json index 0915fd98..334343c5 100644 --- a/data/station/PGC.json +++ b/data/station/PGC.json @@ -45,5 +45,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PGC_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "PGC_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "PGC_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PGC_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PGL.json b/data/station/PGL.json index ae489b78..fcb8c454 100644 --- a/data/station/PGL.json +++ b/data/station/PGL.json @@ -76,5 +76,182 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PGL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "PGL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "PGL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "PGL_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + } + ], + "platforms": [ + { + "id": "PGL_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PGL_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PGL_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW", + "PGLRT_E_CCW" + ], + "serviceStopOccurrences": { + "PGLRT_W_CW": 0, + "PGLRT_E_CCW": 0 + }, + "accessPoints": [] + }, + { + "id": "PGL_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW", + "PGLRT_E_CW" + ], + "serviceStopOccurrences": { + "PGLRT_W_CCW": 0, + "PGLRT_E_CW": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "PGL_XFER_NEL_A_PGLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PGL_NEL_A" + }, + "to": { + "kind": "platform", + "id": "PGL_PGLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PGL_XFER_NEL_A_PGLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PGL_NEL_A" + }, + "to": { + "kind": "platform", + "id": "PGL_PGLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PGL_XFER_NEL_B_PGLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PGL_NEL_B" + }, + "to": { + "kind": "platform", + "id": "PGL_PGLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PGL_XFER_NEL_B_PGLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PGL_NEL_B" + }, + "to": { + "kind": "platform", + "id": "PGL_PGLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/PGP.json b/data/station/PGP.json index f7e39c90..410083f9 100644 --- a/data/station/PGP.json +++ b/data/station/PGP.json @@ -24,5 +24,53 @@ "punggol-waterway-park", "punggol-point-park" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "PGP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "PGP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "PGP_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "PGP_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/PMN.json b/data/station/PMN.json index 54ca6dd3..e56abe20 100644 --- a/data/station/PMN.json +++ b/data/station/PMN.json @@ -137,5 +137,161 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PMN_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PMN_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "PMN_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PMN_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PMN_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PMN_DTL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PMN_DTL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "PMN_XFER_CCL_A_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PMN_CCL_A" + }, + "to": { + "kind": "platform", + "id": "PMN_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PMN_XFER_CCL_A_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PMN_CCL_A" + }, + "to": { + "kind": "platform", + "id": "PMN_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PMN_XFER_CCL_B_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PMN_CCL_B" + }, + "to": { + "kind": "platform", + "id": "PMN_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PMN_XFER_CCL_B_DTL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PMN_CCL_B" + }, + "to": { + "kind": "platform", + "id": "PMN_DTL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/PND.json b/data/station/PND.json index 4cb74b44..8189bb39 100644 --- a/data/station/PND.json +++ b/data/station/PND.json @@ -61,5 +61,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PND_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PND_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "PND_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PNR.json b/data/station/PNR.json index 4db33982..8861f801 100644 --- a/data/station/PNR.json +++ b/data/station/PNR.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PNR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Jurong West Street 63" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PNR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Jurong West Street 63" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "PNR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PNR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PNX.json b/data/station/PNX.json index 062ca786..76c5dc61 100644 --- a/data/station/PNX.json +++ b/data/station/PNX.json @@ -60,5 +60,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PNX_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PNX_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 1, + "BPLRT_B": 1 + }, + "accessPoints": [] + }, + { + "id": "PNX_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PPJ.json b/data/station/PPJ.json index 7bd7401d..030c00ed 100644 --- a/data/station/PPJ.json +++ b/data/station/PPJ.json @@ -61,5 +61,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PPJ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Pasir Panjang Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CPPJ_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CPPJ_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PSR.json b/data/station/PSR.json index 5d3999b2..a30096bf 100644 --- a/data/station/PSR.json +++ b/data/station/PSR.json @@ -59,5 +59,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PSR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PSR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "PSR_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PSR_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PTP.json b/data/station/PTP.json index 9c8c0325..1e08b0bc 100644 --- a/data/station/PTP.json +++ b/data/station/PTP.json @@ -61,5 +61,64 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PTP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PTP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "PTP_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "PTP_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PTP_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PTR.json b/data/station/PTR.json index 0be76773..5b602ab3 100644 --- a/data/station/PTR.json +++ b/data/station/PTR.json @@ -62,5 +62,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PTR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PTR_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "PTR_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/PYL.json b/data/station/PYL.json index 6ce12e3c..191038ef 100644 --- a/data/station/PYL.json +++ b/data/station/PYL.json @@ -103,5 +103,205 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "PYL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "PYL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PYL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PYL_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "PYL_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "PYL_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "PYL_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PYL_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "PYL_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PYL_CCL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "boardingStatus": "not_in_service", + "lineId": "CCL", + "serviceIds": [], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PYL_CCL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "boardingStatus": "not_in_service", + "lineId": "CCL", + "serviceIds": [], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "PYL_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "PYL_XFER_EWL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PYL_EWL_A" + }, + "to": { + "kind": "platform", + "id": "PYL_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PYL_XFER_EWL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PYL_EWL_A" + }, + "to": { + "kind": "platform", + "id": "PYL_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PYL_XFER_EWL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PYL_EWL_B" + }, + "to": { + "kind": "platform", + "id": "PYL_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "PYL_XFER_EWL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "PYL_EWL_B" + }, + "to": { + "kind": "platform", + "id": "PYL_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/QUE.json b/data/station/QUE.json index fa683f52..16ef6167 100644 --- a/data/station/QUE.json +++ b/data/station/QUE.json @@ -62,5 +62,65 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "QUE_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "QUE_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "QUE_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "QUE_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "QUE_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "QUE_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/RCR.json b/data/station/RCR.json index d0697442..ed402cb5 100644 --- a/data/station/RCR.json +++ b/data/station/RCR.json @@ -61,5 +61,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "RCR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "RCR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "RCR_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "RCR_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/RDH.json b/data/station/RDH.json index e861e502..7d15112c 100644 --- a/data/station/RDH.json +++ b/data/station/RDH.json @@ -61,5 +61,56 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "RDH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tiong Bahru Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "RDH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tiong Bahru Road" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "RDH_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "RDH_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/RFP.json b/data/station/RFP.json index 970586fb..f3207274 100644 --- a/data/station/RFP.json +++ b/data/station/RFP.json @@ -104,5 +104,216 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "RFP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_H", + "label": "H", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_I", + "label": "I", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_J", + "label": "J", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_K", + "label": "K", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_L", + "label": "L", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "RFP_EXIT_M", + "label": "M", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "RFP_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "RFP_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "RFP_EWL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "RFP_NSL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "RFP_XFER_A_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "RFP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "RFP_NSL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "RFP_XFER_C_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "RFP_EWL_C" + }, + "to": { + "kind": "platform", + "id": "RFP_NSL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": 0, + "classification": "same_platform", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "RFP_XFER_EWL_A_NSL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "RFP_EWL_A" + }, + "to": { + "kind": "platform", + "id": "RFP_NSL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "RFP_XFER_NSL_B_EWL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "RFP_NSL_B" + }, + "to": { + "kind": "platform", + "id": "RFP_EWL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/RIV.json b/data/station/RIV.json index cb31c294..239c6c5b 100644 --- a/data/station/RIV.json +++ b/data/station/RIV.json @@ -30,5 +30,45 @@ "punggol-waterway-park", "punggol-plaza" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "RIV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "RIV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "RIV_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "RIV_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/RMB.json b/data/station/RMB.json index 08cd9feb..edcad55d 100644 --- a/data/station/RMB.json +++ b/data/station/RMB.json @@ -23,5 +23,51 @@ "sengkang-sports-and-recreation-centre", "compass-one" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "RMB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "RMB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "RMB_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "RMB_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/RNG.json b/data/station/RNG.json index c76fda4f..6e0e0557 100644 --- a/data/station/RNG.json +++ b/data/station/RNG.json @@ -24,5 +24,51 @@ "sengkang-sports-complex", "sengkang-general-hospital" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "RNG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "RNG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "RNG_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW" + ], + "accessPoints": [] + }, + { + "id": "RNG_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/RNJ.json b/data/station/RNJ.json index ca6d6639..8f9b098b 100644 --- a/data/station/RNJ.json +++ b/data/station/RNJ.json @@ -24,5 +24,51 @@ "compass-one", "anchorvale-community-club" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "RNJ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "RNJ_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "RNJ_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "RNJ_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/SAV.json b/data/station/SAV.json index f37bede8..7341dbf5 100644 --- a/data/station/SAV.json +++ b/data/station/SAV.json @@ -60,5 +60,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SAV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SAV_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "SAV_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "SAV_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SBW.json b/data/station/SBW.json index 58672f64..66906f68 100644 --- a/data/station/SBW.json +++ b/data/station/SBW.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SBW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sembawang Way" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SBW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sembawang Way" + ], + "paidArea": false + }, + { + "id": "SBW_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sembawang Way" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SBW_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Sembawang Way" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "SBW_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SBW_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SDM.json b/data/station/SDM.json index e25bc817..4b023aa3 100644 --- a/data/station/SDM.json +++ b/data/station/SDM.json @@ -79,5 +79,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SDM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "SDM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "CSDM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CSDM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SER.json b/data/station/SER.json index c0ec9ff6..6b7f338c 100644 --- a/data/station/SER.json +++ b/data/station/SER.json @@ -103,5 +103,204 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SER_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SER_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SER_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SER_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SER_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SER_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SER_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SER_EXIT_H", + "label": "H", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SER_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SER_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SER_CCL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "SER_CCL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "SER_XFER_NEL_A_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SER_NEL_A" + }, + "to": { + "kind": "platform", + "id": "SER_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SER_XFER_NEL_A_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SER_NEL_A" + }, + "to": { + "kind": "platform", + "id": "SER_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SER_XFER_NEL_B_CCL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SER_NEL_B" + }, + "to": { + "kind": "platform", + "id": "SER_CCL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SER_XFER_NEL_B_CCL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SER_NEL_B" + }, + "to": { + "kind": "platform", + "id": "SER_CCL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/SGL.json b/data/station/SGL.json index 6984d3c0..3091dd47 100644 --- a/data/station/SGL.json +++ b/data/station/SGL.json @@ -61,5 +61,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SGL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "SGL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "SGL_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "SGL_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SGL_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "SGL_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SGR.json b/data/station/SGR.json index e3fdda58..de819b9e 100644 --- a/data/station/SGR.json +++ b/data/station/SGR.json @@ -62,5 +62,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SGR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SGR_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "SGR_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SHV.json b/data/station/SHV.json index 0a760137..1634681c 100644 --- a/data/station/SHV.json +++ b/data/station/SHV.json @@ -62,5 +62,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SHV_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SHV_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 1, + "BPLRT_B": 1 + }, + "accessPoints": [] + }, + { + "id": "SHV_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SHW.json b/data/station/SHW.json index 11142fd4..1e079f75 100644 --- a/data/station/SHW.json +++ b/data/station/SHW.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SHW_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SHW_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SHW_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SHW_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "SHW_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "SHW_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TSHW_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TSHW_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SIM.json b/data/station/SIM.json index b09a9655..70dd8c63 100644 --- a/data/station/SIM.json +++ b/data/station/SIM.json @@ -61,5 +61,47 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SIM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Simei Street 3" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "SIM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SIM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SKG.json b/data/station/SKG.json index 66d8961d..7ce62beb 100644 --- a/data/station/SKG.json +++ b/data/station/SKG.json @@ -71,5 +71,176 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SKG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SKG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SKG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "SKG_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + } + ], + "platforms": [ + { + "id": "SKG_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SKG_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SKG_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CCW", + "SKLRT_W_CW" + ], + "serviceStopOccurrences": { + "SKLRT_E_CCW": 0, + "SKLRT_W_CW": 0 + }, + "accessPoints": [] + }, + { + "id": "SKG_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_E_CW", + "SKLRT_W_CCW" + ], + "serviceStopOccurrences": { + "SKLRT_E_CW": 0, + "SKLRT_W_CCW": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "SKG_XFER_NEL_A_SKLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SKG_NEL_A" + }, + "to": { + "kind": "platform", + "id": "SKG_SKLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SKG_XFER_NEL_A_SKLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SKG_NEL_A" + }, + "to": { + "kind": "platform", + "id": "SKG_SKLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SKG_XFER_NEL_B_SKLRT_1", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SKG_NEL_B" + }, + "to": { + "kind": "platform", + "id": "SKG_SKLRT_1" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "SKG_XFER_NEL_B_SKLRT_2", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "SKG_NEL_B" + }, + "to": { + "kind": "platform", + "id": "SKG_SKLRT_2" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/SMD.json b/data/station/SMD.json index 3b9eaa5f..afa6c341 100644 --- a/data/station/SMD.json +++ b/data/station/SMD.json @@ -24,5 +24,53 @@ "punggol-town-hub", "coney-island-park" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "SMD_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "SMD_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "SMD_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "SMD_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/SMG.json b/data/station/SMG.json index 042a7136..9319917b 100644 --- a/data/station/SMG.json +++ b/data/station/SMG.json @@ -24,5 +24,51 @@ "punggol-digital-district", "seaside-walk" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "SMG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SMG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "SMG_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "SMG_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/SMK.json b/data/station/SMK.json index c6cd7300..dea232be 100644 --- a/data/station/SMK.json +++ b/data/station/SMK.json @@ -24,5 +24,45 @@ "punggol-plaza", "waterway-point" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "SMK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "SMK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SMK_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "SMK_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/SNJ.json b/data/station/SNJ.json index b5433002..343cb430 100644 --- a/data/station/SNJ.json +++ b/data/station/SNJ.json @@ -61,5 +61,39 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SNJ_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SNJ_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_B" + ], + "accessPoints": [] + }, + { + "id": "SNJ_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A" + ], + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SOM.json b/data/station/SOM.json index afe3b7d2..75fe21e3 100644 --- a/data/station/SOM.json +++ b/data/station/SOM.json @@ -62,5 +62,65 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SOM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SOM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SOM_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "SOM_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "SOM_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "SOM_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/SPL.json b/data/station/SPL.json index 2433dac4..e3507819 100644 --- a/data/station/SPL.json +++ b/data/station/SPL.json @@ -60,5 +60,71 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "SPL_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SPL_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "SPL_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TSPL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TSPL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/STK.json b/data/station/STK.json index 3532b19e..593866e5 100644 --- a/data/station/STK.json +++ b/data/station/STK.json @@ -24,5 +24,45 @@ "punggol-plaza", "waterway-point" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "STK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "STK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "STK_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "STK_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/STV.json b/data/station/STV.json index 0b12e1b7..393081e1 100644 --- a/data/station/STV.json +++ b/data/station/STV.json @@ -103,5 +103,180 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "STV_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "STV_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "STV_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "STV_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "STV_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "STV_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "STV_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "STV_TEL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "STV_TEL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "STV_XFER_DTL_A_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "STV_DTL_A" + }, + "to": { + "kind": "platform", + "id": "STV_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "STV_XFER_DTL_A_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "STV_DTL_A" + }, + "to": { + "kind": "platform", + "id": "STV_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "STV_XFER_DTL_B_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "STV_DTL_B" + }, + "to": { + "kind": "platform", + "id": "STV_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "STV_XFER_DTL_B_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "STV_DTL_B" + }, + "to": { + "kind": "platform", + "id": "STV_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/TAM.json b/data/station/TAM.json index e42e25ae..1eb94dba 100644 --- a/data/station/TAM.json +++ b/data/station/TAM.json @@ -103,5 +103,180 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TAM_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-18", + "paidArea": false + }, + { + "id": "TAM_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-18", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TAM_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TAM_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TAM_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "TAM_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "TAM_XFER_EWL_A_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "TAM_EWL_A" + }, + "to": { + "kind": "platform", + "id": "TAM_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TAM_XFER_EWL_A_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "TAM_EWL_A" + }, + "to": { + "kind": "platform", + "id": "TAM_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TAM_XFER_EWL_B_DTL_A", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "TAM_EWL_B" + }, + "to": { + "kind": "platform", + "id": "TAM_DTL_A" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TAM_XFER_EWL_B_DTL_B", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "TAM_EWL_B" + }, + "to": { + "kind": "platform", + "id": "TAM_DTL_B" + }, + "paidArea": false, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "out_of_station", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/TAP.json b/data/station/TAP.json index 123efce3..e6c00e57 100644 --- a/data/station/TAP.json +++ b/data/station/TAP.json @@ -61,5 +61,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TAP_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TAP_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TAP_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TAP_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TAP_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TAP_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TCR.json b/data/station/TCR.json index fb817786..2623193c 100644 --- a/data/station/TCR.json +++ b/data/station/TCR.json @@ -62,5 +62,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TCR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Pioneer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TCR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Pioneer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TCR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TCR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TIB.json b/data/station/TIB.json index 6959a309..9b1f60f1 100644 --- a/data/station/TIB.json +++ b/data/station/TIB.json @@ -62,5 +62,56 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TIB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tiong Bahru Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TIB_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tiong Bahru Road" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "TIB_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TIB_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TKG.json b/data/station/TKG.json index fbf39561..e3a5cd54 100644 --- a/data/station/TKG.json +++ b/data/station/TKG.json @@ -24,5 +24,51 @@ "sengkang-general-hospital", "sengkang-sports-centre" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "TKG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TKG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TKG_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "TKG_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/TKK.json b/data/station/TKK.json index b5a6d720..13f25950 100644 --- a/data/station/TKK.json +++ b/data/station/TKK.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TKK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TKK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "TKK_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "TKK_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TKL.json b/data/station/TKL.json index 3386d450..558a1e42 100644 --- a/data/station/TKL.json +++ b/data/station/TKL.json @@ -24,5 +24,51 @@ "waterway-point", "punggol-plaza" ], - "townId": "punggol" + "townId": "punggol", + "layout": { + "levels": [], + "exits": [ + { + "id": "TKL_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + }, + { + "id": "TKL_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "lift": true + } + } + ], + "platforms": [ + { + "id": "TKL_PGLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "TKL_PGLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "PGLRT", + "serviceIds": [ + "PGLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/TKT.json b/data/station/TKT.json index 230dec89..d5756fac 100644 --- a/data/station/TKT.json +++ b/data/station/TKT.json @@ -62,5 +62,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TKT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "TKT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "TKT_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TKT_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TKT_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TKW.json b/data/station/TKW.json index e571906f..9b0ac3d6 100644 --- a/data/station/TKW.json +++ b/data/station/TKW.json @@ -61,5 +61,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TKW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TKW_BPLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 1, + "BPLRT_B": 1 + }, + "accessPoints": [] + }, + { + "id": "TKW_BPLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "BPLRT", + "serviceIds": [ + "BPLRT_A", + "BPLRT_B" + ], + "serviceStopOccurrences": { + "BPLRT_A": 0, + "BPLRT_B": 0 + }, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TLA.json b/data/station/TLA.json index b0b68e3d..30a9ace9 100644 --- a/data/station/TLA.json +++ b/data/station/TLA.json @@ -63,5 +63,57 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TLA_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TLA_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "TLA_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TLA_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "TLA_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TLB.json b/data/station/TLB.json index a7e1a6bc..6ef709b1 100644 --- a/data/station/TLB.json +++ b/data/station/TLB.json @@ -62,5 +62,49 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TLB_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Telok Blangah Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CTLB_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CTLB_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TLK.json b/data/station/TLK.json index f81ca693..dc917ee2 100644 --- a/data/station/TLK.json +++ b/data/station/TLK.json @@ -44,5 +44,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TLK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tuas West Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TLK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Tuas West Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TLK_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TLK_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TNG.json b/data/station/TNG.json index 4bf2627c..128d32e7 100644 --- a/data/station/TNG.json +++ b/data/station/TNG.json @@ -24,5 +24,45 @@ "compass-one", "sengkang-sports-complex" ], - "townId": "sengkang" + "townId": "sengkang", + "layout": { + "levels": [], + "exits": [ + { + "id": "TNG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "TNG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TNG_SKLRT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CW" + ], + "accessPoints": [] + }, + { + "id": "TNG_SKLRT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "lineId": "SKLRT", + "serviceIds": [ + "SKLRT_W_CCW" + ], + "accessPoints": [] + } + ], + "transferPaths": [] + } } diff --git a/data/station/TNM.json b/data/station/TNM.json index 53ff880c..189a1761 100644 --- a/data/station/TNM.json +++ b/data/station/TNM.json @@ -75,5 +75,190 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TNM_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "roadNames": [ + "New Upper Changi Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TNM_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "roadNames": [ + "New Upper Changi Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TNM_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TNM_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "boardingStatus": "not_in_service", + "lineId": "EWL", + "serviceIds": [], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TNM_EWL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "boardingStatus": "not_in_service", + "lineId": "EWL", + "serviceIds": [], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TNM_EWL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TNM_EWL_E", + "label": "E", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TNM_EWL_F", + "label": "F", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "TNM_XFER_EWL_A_D", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "TNM_EWL_A" + }, + "to": { + "kind": "platform", + "id": "TNM_EWL_D" + }, + "paidArea": true, + "modes": [ + "walk", + "escalator", + "lift" + ], + "levelChange": 0, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TNM_XFER_EWL_A_E", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "TNM_EWL_A" + }, + "to": { + "kind": "platform", + "id": "TNM_EWL_E" + }, + "paidArea": true, + "modes": [ + "walk", + "escalator", + "lift" + ], + "levelChange": 0, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TNM_XFER_EWL_F_D", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "TNM_EWL_F" + }, + "to": { + "kind": "platform", + "id": "TNM_EWL_D" + }, + "paidArea": true, + "modes": [ + "walk", + "escalator", + "lift" + ], + "levelChange": 0, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "TNM_XFER_EWL_F_E", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "TNM_EWL_F" + }, + "to": { + "kind": "platform", + "id": "TNM_EWL_E" + }, + "paidArea": true, + "modes": [ + "walk", + "escalator", + "lift" + ], + "levelChange": 0, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/TPE.json b/data/station/TPE.json index b7fbd11b..b6e3689e 100644 --- a/data/station/TPE.json +++ b/data/station/TPE.json @@ -62,5 +62,75 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TPE_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TPE_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TPE_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TPE_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "TPE_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "TPE_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TPG.json b/data/station/TPG.json index 13a34e11..10ee29bd 100644 --- a/data/station/TPG.json +++ b/data/station/TPG.json @@ -62,5 +62,95 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TPG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_H", + "label": "H", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_J", + "label": "J", + "lastUpdated": "2026-07-16", + "paidArea": false + }, + { + "id": "TPG_EXIT_K", + "label": "K", + "lastUpdated": "2026-07-16", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TPG_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TPG_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TPW.json b/data/station/TPW.json index 32f1d47b..bd5c27b8 100644 --- a/data/station/TPW.json +++ b/data/station/TPW.json @@ -62,5 +62,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TPW_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "TPW_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "TPW_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "TPW_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TRH.json b/data/station/TRH.json index c939fe6a..8874a4ac 100644 --- a/data/station/TRH.json +++ b/data/station/TRH.json @@ -62,5 +62,47 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TRH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-19", + "paidArea": false + }, + { + "id": "TRH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-19", + "paidArea": false + } + ], + "platforms": [ + { + "id": "TRH_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TRH_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TSG.json b/data/station/TSG.json index f1ba6937..ef86067f 100644 --- a/data/station/TSG.json +++ b/data/station/TSG.json @@ -61,5 +61,70 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TSG_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Paya Lebar Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TSG_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Paya Lebar Road" + ], + "paidArea": false + }, + { + "id": "TSG_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Paya Lebar Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "CTSG_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CCW", + "CCL_LOOP_CCW" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "CTSG_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "CCL", + "serviceIds": [ + "CCL_BRANCH_CW", + "CCL_LOOP_CW" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/TWR.json b/data/station/TWR.json index 1305c699..ee556363 100644 --- a/data/station/TWR.json +++ b/data/station/TWR.json @@ -61,5 +61,59 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "TWR_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Pioneer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "TWR_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Pioneer Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TWR_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "TWR_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_MAIN_W" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/UBI.json b/data/station/UBI.json index 7e901d91..2ff813b0 100644 --- a/data/station/UBI.json +++ b/data/station/UBI.json @@ -60,5 +60,55 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "UBI_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "UBI_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "UBI_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "UBI_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/UPC.json b/data/station/UPC.json index 272561c5..9e62e987 100644 --- a/data/station/UPC.json +++ b/data/station/UPC.json @@ -61,5 +61,75 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "UPC_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "UPC_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "UPC_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "UPC_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + } + ], + "platforms": [ + { + "id": "UPC_DTL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "UPC_DTL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_E" + ], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/UTS.json b/data/station/UTS.json index 5b1634ce..7c4c3e59 100644 --- a/data/station/UTS.json +++ b/data/station/UTS.json @@ -62,5 +62,95 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "UTS_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "UTS_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "UTS_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "UTS_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "UTS_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Upper Thomson Road" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TUTS_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TUTS_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/WDL.json b/data/station/WDL.json index 16fb9d2d..6ba9a26a 100644 --- a/data/station/WDL.json +++ b/data/station/WDL.json @@ -103,5 +103,192 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "WDL_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "WDL_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "WDL_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "WDL_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDL_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDL_EXIT_6", + "label": "6", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDL_EXIT_7", + "label": "7", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "WDL_NSL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "WDL_NSL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "WDL_TEL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "WDL_TEL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "WDL_XFER_NSL_A_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "WDL_NSL_A" + }, + "to": { + "kind": "platform", + "id": "WDL_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "WDL_XFER_NSL_A_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "WDL_NSL_A" + }, + "to": { + "kind": "platform", + "id": "WDL_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "WDL_XFER_NSL_B_TEL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "WDL_NSL_B" + }, + "to": { + "kind": "platform", + "id": "WDL_TEL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "WDL_XFER_NSL_B_TEL_D", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "WDL_NSL_B" + }, + "to": { + "kind": "platform", + "id": "WDL_TEL_D" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/WDN.json b/data/station/WDN.json index decc8338..645f2d80 100644 --- a/data/station/WDN.json +++ b/data/station/WDN.json @@ -45,5 +45,53 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "WDN_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDN_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-18", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "WDN_TEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "WDN_TEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/WDS.json b/data/station/WDS.json index eac73087..f601b260 100644 --- a/data/station/WDS.json +++ b/data/station/WDS.json @@ -62,5 +62,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "WDS_EXIT_1", + "label": "1", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDS_EXIT_2", + "label": "2", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDS_EXIT_3", + "label": "3", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDS_EXIT_4", + "label": "4", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "WDS_EXIT_5", + "label": "5", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "TWDS_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_S" + ], + "doorCount": 20, + "accessPoints": [] + }, + { + "id": "TWDS_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "TEL", + "serviceIds": [ + "TEL_MAIN_N" + ], + "doorCount": 20, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/WLH.json b/data/station/WLH.json index 511f8abf..92986068 100644 --- a/data/station/WLH.json +++ b/data/station/WLH.json @@ -62,5 +62,61 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "WLH_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "WLH_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "WLH_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "WLH_NEL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "WLH_NEL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NEL", + "serviceIds": [ + "NEL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/XPO.json b/data/station/XPO.json index d3e4ab70..2a13c222 100644 --- a/data/station/XPO.json +++ b/data/station/XPO.json @@ -92,5 +92,198 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "XPO_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "XPO_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "XPO_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "XPO_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "XPO_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-17", + "paidArea": false, + "accessibility": { + "stepFree": true, + "lift": true + } + }, + { + "id": "XPO_EXIT_F", + "label": "F", + "lastUpdated": "2026-07-17", + "paidArea": false + }, + { + "id": "XPO_EXIT_G", + "label": "G", + "lastUpdated": "2026-07-17", + "paidArea": false + } + ], + "platforms": [ + { + "id": "XPO_EWL_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_E" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "XPO_EWL_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "EWL", + "serviceIds": [ + "EWL_CG_W" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "XPO_DTL_C", + "label": "C", + "lastUpdated": "2026-07-18", + "lineId": "DTL", + "serviceIds": [ + "DTL_MAIN_W" + ], + "doorCount": 12, + "accessPoints": [] + }, + { + "id": "XPO_DTL_D", + "label": "D", + "lastUpdated": "2026-07-18", + "boardingStatus": "alighting_only", + "lineId": "DTL", + "serviceIds": [], + "doorCount": 12, + "accessPoints": [] + } + ], + "transferPaths": [ + { + "id": "XPO_XFER_EWL_A_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "XPO_EWL_A" + }, + "to": { + "kind": "platform", + "id": "XPO_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "XPO_XFER_EWL_B_DTL_C", + "lastUpdated": "2026-07-18", + "from": { + "kind": "platform", + "id": "XPO_EWL_B" + }, + "to": { + "kind": "platform", + "id": "XPO_DTL_C" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "XPO_XFER_DTL_D_EWL_A", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "XPO_DTL_D" + }, + "to": { + "kind": "platform", + "id": "XPO_EWL_A" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + }, + { + "id": "XPO_XFER_DTL_D_EWL_B", + "lastUpdated": "2026-07-19", + "from": { + "kind": "platform", + "id": "XPO_DTL_D" + }, + "to": { + "kind": "platform", + "id": "XPO_EWL_B" + }, + "paidArea": true, + "modes": [ + "walk" + ], + "levelChange": null, + "classification": "unknown", + "estimatedTraversalSeconds": null, + "distanceMeters": null + } + ] } } diff --git a/data/station/YCK.json b/data/station/YCK.json index 67eb14be..414cd94a 100644 --- a/data/station/YCK.json +++ b/data/station/YCK.json @@ -61,5 +61,62 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "YCK_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YCK_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YCK_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "YCK_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "YCK_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/YIS.json b/data/station/YIS.json index a0c9afc3..04767848 100644 --- a/data/station/YIS.json +++ b/data/station/YIS.json @@ -62,5 +62,89 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "YIS_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YIS_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YIS_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false + }, + { + "id": "YIS_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YIS_EXIT_E", + "label": "E", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Yishun Avenue 2" + ], + "paidArea": false + } + ], + "platforms": [ + { + "id": "YIS_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "YIS_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/data/station/YWT.json b/data/station/YWT.json index f22c13d3..704b746f 100644 --- a/data/station/YWT.json +++ b/data/station/YWT.json @@ -61,5 +61,80 @@ } } ] + }, + "layout": { + "levels": [], + "exits": [ + { + "id": "YWT_EXIT_A", + "label": "A", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Choa Chu Kang Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YWT_EXIT_B", + "label": "B", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Choa Chu Kang Drive" + ], + "paidArea": false + }, + { + "id": "YWT_EXIT_C", + "label": "C", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Choa Chu Kang Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + }, + { + "id": "YWT_EXIT_D", + "label": "D", + "lastUpdated": "2026-07-16", + "roadNames": [ + "Choa Chu Kang Drive" + ], + "paidArea": false, + "accessibility": { + "stepFree": true + } + } + ], + "platforms": [ + { + "id": "YWT_A", + "label": "A", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_N" + ], + "doorCount": 24, + "accessPoints": [] + }, + { + "id": "YWT_B", + "label": "B", + "lastUpdated": "2026-07-18", + "lineId": "NSL", + "serviceIds": [ + "NSL_MAIN_S" + ], + "doorCount": 24, + "accessPoints": [] + } + ], + "transferPaths": [] } } diff --git a/docs/plans/active/station-layout-data.md b/docs/plans/active/station-layout-data.md index 8c024019..c508197c 100644 --- a/docs/plans/active/station-layout-data.md +++ b/docs/plans/active/station-layout-data.md @@ -52,7 +52,8 @@ Related references: - This plan does not attempt detailed CAD geometry or public wayfinding map rendering. - This plan does not model temporary works, temporary platform closures, or - incident-specific access restrictions as static station layout. + incident-specific access restrictions as static station layout, except for + the current operational status of a durable public exit. - This plan does not add hand-authored page titles or meta descriptions. The site should continue deriving them from canonical station facts. @@ -122,6 +123,11 @@ Layout data is current state. If a station changes, update the embedded layout to the new current state in the same way the canonical station record is updated. +Every level, exit, platform, access point, and transfer path requires a +`lastUpdated` date in `YYYY-MM-DD` form. It records when that individual layout +fact was last verified against its source; update it when the fact is reviewed +or changed, rather than whenever the containing station file is edited. + ## Levels Levels identify station floors for platforms and access points. @@ -129,6 +135,7 @@ Levels identify station floors for platforms and access points. ```json { "id": "B2", + "lastUpdated": "2026-07-19", "index": -2, "name": { "en-SG": "EWL and TEL platforms", @@ -157,6 +164,7 @@ access routing are part of the passenger-facing station layout. { "id": "TAM_EXIT_A", "label": "A", + "lastUpdated": "2026-07-19", "levelId": "L1", "geo": { "latitude": 1.35395, @@ -176,6 +184,9 @@ Initial fields: - `id`: station-local id. - `label`: public exit label such as `A`, `B`, `1`, or `Exit A`. +- `operationalStatus`: optional exceptional current state. Absence means the + exit is open; `temporarily_closed` preserves the exit identity while keeping + wayfinding consumers from routing passengers through it. - `levelId`: optional reference to `layout.levels`. - `geo`: optional exit coordinate when a reviewed source provides it. - `nearbyLandmarkIds`: optional references to existing landmark records. @@ -190,17 +201,23 @@ Rules: - Use `nearbyLandmarkIds` for landmarks already modeled in `data/landmark`; use `roadNames` for roads that are not landmarks. - Keep exit labels as strings because public labels are not always numeric. -- Do not model temporary construction diversions as static exits. +- Keep durable exits in the layout while they are temporarily closed and mark + them with `operationalStatus`; do not model temporary construction diversion + routes as static exits. ## Platforms Platforms represent public boarding areas. They should reference full scheduled -service patterns through `serviceIds`. +service patterns through `serviceIds`. A terminal platform used only to unload +arriving passengers remains part of the layout with `boardingStatus` set to +`alighting_only`. A platform that exists physically but is unavailable for +ordinary passenger service uses `not_in_service`. ```json { "id": "OTP_EWL_A", "label": "A", + "lastUpdated": "2026-07-19", "lineId": "EWL", "levelId": "B2", "serviceIds": ["EWL_MAIN_E"], @@ -214,6 +231,14 @@ Rules: - Use `serviceIds`, not `towardsStationId`. The service path is the source of truth for direction, stopping pattern, and terminal. - Use an array because platforms can host multiple scheduled patterns. +- `serviceStopOccurrences` optionally maps a service id to the zero-based + occurrence of this station in the current service path. It is required when + a loop service visits the station more than once, so consumers can derive the + correct next stop for each platform. +- `serviceIds` must be non-empty for ordinary boarding platforms and empty when + `boardingStatus` is `alighting_only` or `not_in_service`. Non-boardable + platforms do not advertise arriving, occasional, or inactive services as + boardable. - `doorCount` is preferred over enumerating every door when doors have no individual metadata. - Keep `lineId` for simple validation and authoring, even though it can be @@ -228,6 +253,7 @@ wayfinding. They are anchored to doors when possible. { "id": "OTP_EWL_A_ESC_01", "kind": "escalator", + "lastUpdated": "2026-07-19", "nearestDoor": "12", "position": "middle", "connectsToLevelId": "B1", @@ -264,10 +290,15 @@ Rules: ## Transfer Paths Transfer paths describe public movement between platforms or access points. +They are bidirectional: `from` and `to` provide a stable ordering for the two +endpoints and do not restrict traversal direction. Store one record per known +physical path rather than duplicating it in reverse. Direction-specific paths +can be introduced later if the schema gains explicit directionality metadata. ```json { "id": "OTP_EWL_TEL_PAID_LINK", + "lastUpdated": "2026-07-19", "from": { "kind": "platform", "id": "OTP_EWL_A" @@ -313,6 +344,9 @@ Initial `classification` values: The classification is intentionally coarse. It is useful for routing and user interfaces without pretending that all stations have measured distance data. +Transfer endpoint objects are lightweight references and therefore contain only +`kind` and `id`; provenance belongs to the transfer path and referenced layout +record rather than being duplicated on each reference. ## Validation @@ -328,6 +362,8 @@ Add validation that catches: - platform `lineId` values that do not exist; - platform `levelId` values that do not exist in `layout.levels`; - platform `serviceIds` values that do not exist; +- platform services that omit or exceed a required repeated-stop occurrence in + an open service revision; - services whose `lineId` differs from the platform `lineId`; - transfer endpoints that do not reference an existing level, platform, or access point; diff --git a/packages/core/src/schema/Station.test.ts b/packages/core/src/schema/Station.test.ts index 251787ef..958a88bd 100644 --- a/packages/core/src/schema/Station.test.ts +++ b/packages/core/src/schema/Station.test.ts @@ -180,6 +180,7 @@ describe('StationSchema', () => { { id: 'B2', index: -2, + lastUpdated: '2026-07-18', name: { 'en-SG': 'Platforms', 'zh-Hans': null, @@ -192,6 +193,8 @@ describe('StationSchema', () => { { id: 'KET_EXIT_A', label: 'A', + lastUpdated: '2026-07-18', + operationalStatus: 'temporarily_closed', levelId: 'B2', paidArea: false, }, @@ -200,6 +203,7 @@ describe('StationSchema', () => { { id: 'KET_ISL_A', label: 'A', + lastUpdated: '2026-07-18', lineId: 'ISL', levelId: 'B2', serviceIds: ['ISL_MAIN_E'], @@ -208,6 +212,7 @@ describe('StationSchema', () => { { id: 'KET_ISL_A_ESC_01', kind: 'escalator', + lastUpdated: '2026-07-18', nearestDoor: '12', position: 'middle', connectsToLevelId: 'B2', @@ -219,6 +224,7 @@ describe('StationSchema', () => { transferPaths: [ { id: 'KET_TRANSFER', + lastUpdated: '2026-07-18', from: { kind: 'platform', id: 'KET_ISL_A', @@ -240,6 +246,31 @@ describe('StationSchema', () => { ).not.toThrow(); }); + it('rejects unknown station exit operational statuses', () => { + const result = StationSchema.safeParse({ + ...minimalStation(), + layout: { + levels: [], + exits: [ + { + id: 'KET_EXIT_A', + label: 'A', + lastUpdated: '2026-07-18', + operationalStatus: 'permanently_closed', + paidArea: false, + }, + ], + platforms: [], + transferPaths: [], + }, + }); + + expect(result.success).toBe(false); + expect(result.error?.issues[0]?.path.join('.')).toBe( + 'layout.exits.0.operationalStatus', + ); + }); + it('rejects layout platforms without service ids', () => { const result = StationSchema.safeParse({ ...minimalStation(), @@ -250,6 +281,7 @@ describe('StationSchema', () => { { id: 'KET_ISL_A', label: 'A', + lastUpdated: '2026-07-18', lineId: 'ISL', serviceIds: [], accessPoints: [], @@ -264,4 +296,84 @@ describe('StationSchema', () => { 'layout.platforms.0.serviceIds', ); }); + + it('accepts alighting-only platforms without service ids', () => { + expect(() => + StationSchema.parse({ + ...minimalStation(), + layout: { + levels: [], + exits: [], + platforms: [ + { + id: 'KET_ISL_A', + label: 'A', + lastUpdated: '2026-07-18', + boardingStatus: 'alighting_only', + lineId: 'ISL', + serviceIds: [], + accessPoints: [], + }, + ], + transferPaths: [], + }, + }), + ).not.toThrow(); + }); + + it('rejects service ids on non-boardable platforms', () => { + const result = StationSchema.safeParse({ + ...minimalStation(), + layout: { + levels: [], + exits: [], + platforms: [ + { + id: 'KET_ISL_A', + label: 'A', + lastUpdated: '2026-07-18', + boardingStatus: 'alighting_only', + lineId: 'ISL', + serviceIds: ['ISL_MAIN_E'], + accessPoints: [], + }, + ], + transferPaths: [], + }, + }); + + expect(result.success).toBe(false); + expect(result.error?.issues[0]?.path.join('.')).toBe( + 'layout.platforms.0.serviceIds', + ); + }); + + it('rejects stop occurrences for services not served by the platform', () => { + const result = StationSchema.safeParse({ + ...minimalStation(), + layout: { + levels: [], + exits: [], + platforms: [ + { + id: 'KET_ISL_A', + label: 'A', + lastUpdated: '2026-07-18', + lineId: 'ISL', + serviceIds: ['ISL_MAIN_E'], + serviceStopOccurrences: { + ISL_MAIN_W: 1, + }, + accessPoints: [], + }, + ], + transferPaths: [], + }, + }); + + expect(result.success).toBe(false); + expect(result.error?.issues[0]?.path.join('.')).toBe( + 'layout.platforms.0.serviceStopOccurrences.ISL_MAIN_W', + ); + }); }); diff --git a/packages/core/src/schema/Station.ts b/packages/core/src/schema/Station.ts index 60e2c885..edbd45b7 100644 --- a/packages/core/src/schema/Station.ts +++ b/packages/core/src/schema/Station.ts @@ -137,12 +137,22 @@ export const StationLayoutLevelSchema = z.object({ id: z.string(), index: z.number().int(), name: TranslationsSchema, + lastUpdated: z.iso.date(), }); export type StationLayoutLevel = z.infer; +export const StationLayoutExitOperationalStatusSchema = z.enum([ + 'temporarily_closed', +]); +export type StationLayoutExitOperationalStatus = z.infer< + typeof StationLayoutExitOperationalStatusSchema +>; + export const StationLayoutExitSchema = z.object({ id: z.string(), label: z.string(), + lastUpdated: z.iso.date(), + operationalStatus: StationLayoutExitOperationalStatusSchema.optional(), levelId: z.string().optional(), geo: z .object({ @@ -165,6 +175,7 @@ export type StationLayoutExit = z.infer; export const StationLayoutAccessPointSchema = z.object({ id: z.string(), kind: StationLayoutAccessPointKindSchema, + lastUpdated: z.iso.date(), nearestDoor: z.string().optional(), position: StationLayoutAccessPointPositionSchema, connectsToLevelId: z.string().optional(), @@ -174,15 +185,59 @@ export type StationLayoutAccessPoint = z.infer< typeof StationLayoutAccessPointSchema >; -export const StationLayoutPlatformSchema = z.object({ - id: z.string(), - label: z.string(), - lineId: z.string(), - levelId: z.string().optional(), - serviceIds: z.array(z.string()).nonempty(), - doorCount: z.number().int().positive().optional(), - accessPoints: z.array(StationLayoutAccessPointSchema), -}); +export const StationLayoutPlatformBoardingStatusSchema = z.enum([ + 'alighting_only', + 'not_in_service', +]); +export type StationLayoutPlatformBoardingStatus = z.infer< + typeof StationLayoutPlatformBoardingStatusSchema +>; + +export const StationLayoutPlatformSchema = z + .object({ + id: z.string(), + label: z.string(), + lastUpdated: z.iso.date(), + boardingStatus: StationLayoutPlatformBoardingStatusSchema.optional(), + lineId: z.string(), + levelId: z.string().optional(), + serviceIds: z.array(z.string()), + serviceStopOccurrences: z + .record(z.string(), z.number().int().nonnegative()) + .optional(), + doorCount: z.number().int().positive().optional(), + accessPoints: z.array(StationLayoutAccessPointSchema), + }) + .superRefine((platform, context) => { + if (platform.serviceIds.length === 0 && !platform.boardingStatus) { + context.addIssue({ + code: 'custom', + message: + 'serviceIds must not be empty unless the platform is non-boardable', + path: ['serviceIds'], + }); + } + + if (platform.serviceIds.length > 0 && platform.boardingStatus) { + context.addIssue({ + code: 'custom', + message: 'non-boardable platforms must not advertise serviceIds', + path: ['serviceIds'], + }); + } + + for (const serviceId of Object.keys( + platform.serviceStopOccurrences ?? {}, + )) { + if (!platform.serviceIds.includes(serviceId)) { + context.addIssue({ + code: 'custom', + message: 'service stop occurrences must reference a serviceId', + path: ['serviceStopOccurrences', serviceId], + }); + } + } + }); export type StationLayoutPlatform = z.infer; export const StationLayoutTransferEndpointSchema = z.object({ @@ -195,6 +250,7 @@ export type StationLayoutTransferEndpoint = z.infer< export const StationLayoutTransferPathSchema = z.object({ id: z.string(), + lastUpdated: z.iso.date(), from: StationLayoutTransferEndpointSchema, to: StationLayoutTransferEndpointSchema, paidArea: z.boolean(), diff --git a/packages/fs/src/index.test.ts b/packages/fs/src/index.test.ts index b4e342ae..cb2d6b37 100644 --- a/packages/fs/src/index.test.ts +++ b/packages/fs/src/index.test.ts @@ -2882,6 +2882,7 @@ describe('@mrtdown/fs', () => { { id: 'B2', index: -2, + lastUpdated: '2026-07-18', name: { 'en-SG': 'Platforms', 'zh-Hans': null, @@ -2892,6 +2893,7 @@ describe('@mrtdown/fs', () => { { id: 'B2', index: -2, + lastUpdated: '2026-07-18', name: { 'en-SG': 'Duplicate platforms', 'zh-Hans': null, @@ -2904,6 +2906,7 @@ describe('@mrtdown/fs', () => { { id: 'KET_EXIT_A', label: 'A', + lastUpdated: '2026-07-18', levelId: 'MISSING', nearbyLandmarkIds: ['missing-landmark'], paidArea: false, @@ -2911,6 +2914,7 @@ describe('@mrtdown/fs', () => { { id: 'KET_EXIT_B', label: 'a', + lastUpdated: '2026-07-18', paidArea: false, }, ], @@ -2918,6 +2922,7 @@ describe('@mrtdown/fs', () => { { id: 'KET_ISL_A', label: 'A', + lastUpdated: '2026-07-18', lineId: 'ISL', levelId: 'MISSING', serviceIds: ['MISSING_SERVICE'], @@ -2926,6 +2931,7 @@ describe('@mrtdown/fs', () => { { id: 'KET_AP_DUP', kind: 'escalator', + lastUpdated: '2026-07-18', nearestDoor: '25', position: 'middle', connectsToLevelId: 'MISSING', @@ -2935,12 +2941,14 @@ describe('@mrtdown/fs', () => { { id: 'KET_TWL_A', label: 'A', + lastUpdated: '2026-07-18', lineId: 'ISL', - serviceIds: ['TWL_MAIN_N', 'ISL_SKIP_KET'], + serviceIds: ['TWL_MAIN_N', 'ISL_SKIP_KET', 'ISL_REPEAT_KET'], accessPoints: [ { id: 'KET_AP_DUP', kind: 'stairs', + lastUpdated: '2026-07-18', position: 'front', }, ], @@ -2949,6 +2957,7 @@ describe('@mrtdown/fs', () => { transferPaths: [ { id: 'KET_TRANSFER', + lastUpdated: '2026-07-18', from: { kind: 'platform', id: 'MISSING_PLATFORM', @@ -2983,6 +2992,71 @@ describe('@mrtdown/fs', () => { ta: null, }, lineId: 'ISL', + revisions: [ + { + id: 'r_historical', + startAt: '1979-10-01', + endAt: '1980-01-01', + path: { + stations: [ + { + stationId: 'KET', + displayCode: 'ISL1', + }, + ], + }, + operatingHours: { + weekdays: { + start: '05:30', + end: '00:30', + }, + weekends: { + start: '05:30', + end: '00:30', + }, + }, + }, + { + id: 'r_current', + startAt: '1980-01-01', + endAt: null, + path: { + stations: [ + { + stationId: 'HKU', + displayCode: 'ISL2', + }, + ], + }, + operatingHours: { + weekdays: { + start: '05:30', + end: '00:30', + }, + weekends: { + start: '05:30', + end: '00:30', + }, + }, + }, + ], + }, + null, + 2, + )}\n`, + ); + await writeFile( + join(dataDir, 'service/ISL_REPEAT_KET.json'), + `${JSON.stringify( + { + id: 'ISL_REPEAT_KET', + name: { + 'en-SG': 'Kennedy Town Loop Service', + 'zh-Hans': null, + ms: null, + ta: null, + }, + lineId: 'ISL', revisions: [ { id: 'r_current', @@ -2990,10 +3064,18 @@ describe('@mrtdown/fs', () => { endAt: null, path: { stations: [ + { + stationId: 'KET', + displayCode: 'ISL1', + }, { stationId: 'HKU', displayCode: 'ISL2', }, + { + stationId: 'KET', + displayCode: 'ISL1', + }, ], }, operatingHours: { @@ -3061,7 +3143,8 @@ describe('@mrtdown/fs', () => { 'station/KET.json: layout.platforms.0.levelId MISSING does not exist in layout.levels', 'station/KET.json: layout.platforms.0.serviceIds.0 MISSING_SERVICE does not exist in service/', 'station/KET.json: layout.platforms.1.serviceIds.0 TWL_MAIN_N belongs to line TWL, not ISL', - 'station/KET.json: layout.platforms.1.serviceIds.1 ISL_SKIP_KET does not include station KET in any service revision', + 'station/KET.json: layout.platforms.1.serviceIds.1 ISL_SKIP_KET revision r_current does not include station KET in its active service path', + 'station/KET.json: layout.platforms.1.serviceIds.2 ISL_REPEAT_KET visits station KET 2 times in active revision r_current; serviceStopOccurrences.ISL_REPEAT_KET is required', 'station/KET.json: layout.platforms.0.accessPoints.0.connectsToLevelId MISSING does not exist in layout.levels', 'station/KET.json: layout.platforms.0.accessPoints.0.nearestDoor 25 is outside doorCount 24', 'station/KET.json: layout.transferPaths.0.from platform MISSING_PLATFORM does not exist in layout', @@ -3071,6 +3154,51 @@ describe('@mrtdown/fs', () => { ); }); + it('accepts a platform service revision with a scheduled future end', async () => { + const dataDir = await mkdtemp(join(tmpdir(), 'mrtdown-fs-')); + await cp(fixtureDataDir, dataDir, { recursive: true }); + const servicePath = join(dataDir, 'service/ISL_MAIN_E.json'); + const service = JSON.parse(await readFile(servicePath, 'utf8')); + service.revisions[0].endAt = '2026-08-01'; + await writeFile(servicePath, `${JSON.stringify(service, null, 2)}\n`); + + const result = await validateDataRoot(dataDir, ['station']); + + expect(result.ok).toBe(true); + expect(result.errors).toEqual([]); + }); + + it('allows exit-only station layouts with first/last train data', async () => { + const dataDir = await mkdtemp(join(tmpdir(), 'mrtdown-fs-')); + await cp(fixtureDataDir, dataDir, { recursive: true }); + const stationPath = join(dataDir, 'station/KET.json'); + const station = JSON.parse(await readFile(stationPath, 'utf8')); + station.layout = { + levels: [], + exits: [ + { + id: 'KET_EXIT_A', + label: 'A', + lastUpdated: '2026-07-18', + roadNames: ['Rock Hill Street'], + paidArea: false, + accessibility: { + stepFree: true, + }, + }, + ], + platforms: [], + transferPaths: [], + }; + await writeFile(stationPath, `${JSON.stringify(station, null, 2)}\n`); + + const result = await validateDataRoot(dataDir, ['station']); + + expect(result.ok).toBe(true); + expect(result.errors).toEqual([]); + expect(result.checked.station).toBe(fixtureMeta.counts.station); + }); + it('rejects service revisions outside station code active windows', async () => { const dataDir = await mkdtemp(join(tmpdir(), 'mrtdown-fs-')); await mkdir(join(dataDir, 'line'), { recursive: true }); diff --git a/packages/fs/src/validate.ts b/packages/fs/src/validate.ts index affd4ada..87db5c1e 100644 --- a/packages/fs/src/validate.ts +++ b/packages/fs/src/validate.ts @@ -412,10 +412,47 @@ async function validateStationReferences( continue; } - if (!serviceIncludesStation(service.value, station.value.id)) { + const activeRevisions = service.value.revisions.filter( + (revision) => + revision.startAt <= platform.lastUpdated && + (revision.endAt === null || + platform.lastUpdated < revision.endAt), + ); + if (activeRevisions.length === 0) { errors.push( - `${station.path}: layout.platforms.${platformIndex}.serviceIds.${serviceIndex} ${serviceId} does not include station ${station.value.id} in any service revision`, + `${station.path}: layout.platforms.${platformIndex}.serviceIds.${serviceIndex} ${serviceId} does not have a service revision active on ${platform.lastUpdated}`, ); + continue; + } + + for (const revision of activeRevisions) { + const stationOccurrenceCount = revision.path.stations.filter( + (serviceStation) => serviceStation.stationId === station.value.id, + ).length; + if (stationOccurrenceCount === 0) { + errors.push( + `${station.path}: layout.platforms.${platformIndex}.serviceIds.${serviceIndex} ${serviceId} revision ${revision.id} does not include station ${station.value.id} in its active service path`, + ); + continue; + } + + const selectedOccurrence = + platform.serviceStopOccurrences?.[serviceId]; + if ( + stationOccurrenceCount > 1 && + selectedOccurrence === undefined + ) { + errors.push( + `${station.path}: layout.platforms.${platformIndex}.serviceIds.${serviceIndex} ${serviceId} visits station ${station.value.id} ${stationOccurrenceCount} times in active revision ${revision.id}; serviceStopOccurrences.${serviceId} is required`, + ); + } else if ( + selectedOccurrence !== undefined && + selectedOccurrence >= stationOccurrenceCount + ) { + errors.push( + `${station.path}: layout.platforms.${platformIndex}.serviceStopOccurrences.${serviceId} ${selectedOccurrence} is outside ${stationOccurrenceCount} station occurrences in active revision ${revision.id}`, + ); + } } } } @@ -459,7 +496,11 @@ async function validateStationReferences( seenFirstLastTrainServices.set(serviceTiming.serviceId, index); } - if (layout && !layoutPlatformServiceIds.has(serviceTiming.serviceId)) { + if ( + layout && + layout.platforms.length > 0 && + !layoutPlatformServiceIds.has(serviceTiming.serviceId) + ) { errors.push( `${station.path}: firstLastTrain.services.${index}.serviceId ${serviceTiming.serviceId} is not served by any layout platform`, ); diff --git a/scripts/generate-fixtures.mjs b/scripts/generate-fixtures.mjs index 5b3691c6..952a34bc 100644 --- a/scripts/generate-fixtures.mjs +++ b/scripts/generate-fixtures.mjs @@ -363,6 +363,7 @@ function buildStaticEntities() { { id: 'B2', index: -2, + lastUpdated: '2026-07-18', name: translations('Platforms'), }, ], @@ -370,6 +371,7 @@ function buildStaticEntities() { { id: 'KET_EXIT_A', label: 'A', + lastUpdated: '2026-07-18', levelId: 'B2', roadNames: ['Rock Hill Street'], paidArea: false, @@ -383,6 +385,7 @@ function buildStaticEntities() { { id: 'KET_ISL_E', label: '1', + lastUpdated: '2026-07-18', lineId: 'ISL', levelId: 'B2', serviceIds: ['ISL_MAIN_E'], @@ -391,6 +394,7 @@ function buildStaticEntities() { { id: 'KET_ISL_E_LIFT_01', kind: 'lift', + lastUpdated: '2026-07-18', nearestDoor: '12', position: 'middle', connectsToLevelId: 'B2', @@ -401,6 +405,7 @@ function buildStaticEntities() { { id: 'KET_ISL_W', label: '2', + lastUpdated: '2026-07-18', lineId: 'ISL', levelId: 'B2', serviceIds: ['ISL_MAIN_W'], @@ -411,6 +416,7 @@ function buildStaticEntities() { transferPaths: [ { id: 'KET_ISL_CROSS_PLATFORM', + lastUpdated: '2026-07-18', from: { kind: 'platform', id: 'KET_ISL_E',