Skip to content

Added campus map - #871

Closed
SJieNg123 wants to merge 21 commits into
nthumodifications:mainfrom
SJieNg123:main
Closed

Added campus map#871
SJieNg123 wants to merge 21 commits into
nthumodifications:mainfrom
SJieNg123:main

Conversation

@SJieNg123

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI lite review requested due to automatic review settings September 11, 2026 17:05
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

@SJieNg123 is attempting to deploy a commit to the Chew Tzi Hwee's projects Team on Vercel.

A member of the Team first needs to authorize it.

@SJieNg123

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Four unresolved moderate issues remain in refetch handling, asset caching, and unmapped navigation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds an OSM-backed 3D NTHU campus map with generated data, shared utilities, localized UI, and timetable/venue integrations.

Changes:

  • Adds OSM data generation, curation, and campus geometry utilities.
  • Adds Three.js map rendering, search, selection, labels, and navigation.
  • Integrates the map into routes, translations, venues, timetable entries, and builds.
File summaries
File Summary
tools/map-data/src/osmEnvironment.ts OSM geometry and environment processing.
tools/map-data/src/osmEnvironment.test.ts Tests for OSM environment processing.
tools/map-data/src/generate-campus-data.ts Campus data generation pipeline.
tools/map-data/src/curation.ts Map curation and label logic.
tools/map-data/src/curation.test.ts Curation behavior tests.
tools/map-data/README.md Map-data pipeline documentation.
tools/map-data/package.json Map-data tooling scripts and dependencies.
tools/map-data/campus-map-curation.json Curated campus labels and metadata.
README.md Project setup and map documentation.
packages/shared/src/index.ts Shared campus API exports.
packages/shared/src/campus/types.ts Shared campus data models.
packages/shared/src/campus/index.ts Campus module exports.
packages/shared/src/campus/geo.ts Geographic conversion utilities.
packages/shared/src/campus/geo.test.ts Geographic utility tests.
packages/shared/src/campus/buildings.ts Building identity and lookup utilities.
packages/shared/src/campus/buildings.test.ts Building utility tests.
packages/shared/package.json Shared package configuration and scripts.
package.json Repository map-generation scripts.
apps/web/vite.config.ts Vite map chunk and PWA configuration.
apps/web/tsconfig.test.json Test TypeScript configuration.
apps/web/tsconfig.json Web TypeScript configuration.
apps/web/src/router.tsx Campus map route registration.
apps/web/src/features/campusMap/sceneLogic.ts Scene state and interaction logic.
apps/web/src/features/campusMap/sceneLogic.test.ts Scene logic tests.
apps/web/src/features/campusMap/sceneGeometry.ts Scene geometry construction.
apps/web/src/features/campusMap/sceneGeometry.test.ts Scene geometry tests.
apps/web/src/features/campusMap/navigation.ts Building and venue navigation resolution.
apps/web/src/features/campusMap/navigation.test.ts Navigation tests.
apps/web/src/features/campusMap/MapSearch.tsx Map search interface.
apps/web/src/features/campusMap/MapLegend.tsx Map legend interface.
apps/web/src/features/campusMap/index.ts Campus-map feature exports.
apps/web/src/features/campusMap/data.ts Campus dataset loading and query behavior.
apps/web/src/features/campusMap/data.test.ts Campus data loading tests.
apps/web/src/features/campusMap/CampusTrees.tsx Campus tree rendering.
apps/web/src/features/campusMap/CampusScene.tsx Three.js campus scene.
apps/web/src/features/campusMap/CampusMapPage.tsx Campus map page and loading UI.
apps/web/src/features/campusMap/campusData.test.ts Committed campus data consistency tests.
apps/web/src/features/campusMap/CampusCamera.tsx Map camera controls and focus.
apps/web/src/features/campusMap/BuildingMesh.tsx Building mesh rendering.
apps/web/src/features/campusMap/BuildingInfoPanel.tsx Building information panel.
apps/web/src/dictionaries/zh.json Chinese map translations.
apps/web/src/dictionaries/en.json English map translations.
apps/web/src/const/apps.ts Campus map app catalog entry.
apps/web/src/components/Timetable/TimetableItemDrawer.tsx Timetable-to-map integration.
apps/web/src/app/[lang]/(mods-pages)/map/page.tsx Campus map page route.
apps/web/src/app/[lang]/(mods-pages)/(venues)/venues/page.tsx Venue-to-map integration.
apps/web/package.json Three.js and map test dependencies/scripts.
Review details

Suppressed comments (2)

apps/web/src/features/campusMap/CampusMapPage.tsx:153

  • This condition treats a background refetch failure as an initial load failure. TanStack Query retains the previous data while setting error for a failed focus/mount refetch, so a temporary network failure will replace an otherwise usable map with the load-error screen. Render the error only when no data is available, or handle refetch errors separately.
  if (error || !data) {

apps/web/src/features/campusMap/CampusMapPage.tsx:73

  • These settings make every window-focus and route-mount event refetch the full static campus dataset, and each response replaces the data object so the Three.js scene and camera focus are rebuilt unnecessarily. Since the query key already includes CAMPUS_MAP_DATA_CACHE_VERSION, keep the loaded version fresh for the session and only refetch when that key changes.
    staleTime: 0,
    refetchOnMount: "always",
    refetchOnWindowFocus: "always",
  • Files reviewed: 47/49 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

export async function loadCampusMapData(
signal?: AbortSignal,
): Promise<CampusMapData> {
const response = await fetch(CAMPUS_DATA_URL, { signal, cache: "no-store" });
Comment on lines +7 to +9
const identity = venues
?.map((venue) => resolveVenueToCampusIdentity(venue))
.find((candidate) => candidate !== undefined);
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@ImJustChew

Copy link
Copy Markdown
Member

Reviewed this with two independent passes (a codex agent over the full diff plus a manual pass), then verified it in a browser. Nice work — the curation pipeline, the environment layer and the polygon-hole support are a real step up, and the generated data is noticeably tighter than what #838 shipped.

Two logistics notes first:

  1. main already carries the first version of this map — fix: improve local web development setup and updated readme.md  #838 squash-merged your earlier commits. This branch was cut before that, so GitHub sees it as 257 files divergent and a direct merge would have reverted a fair amount of recent main (recruitment, OIDC consent, search fallback, the timetable grid work).
  2. I've merged your branch with current main, resolved the conflicts and opened feat(map): campus map curation, environment layer and timetable link (#871) #872 with the result. Your commits are preserved. Nothing for you to do here.

Conflict resolutions worth knowing about

  • apps/web and packages/shared "test" scripts: the branch narrows both back to a single path (bun test src/features/campusMap, bun test src/campus). test: run every test file instead of a fixed path per workspace #865 had just changed those to bun test src so every test file runs. Kept main's version.
  • timetable.course_actions added course_details, add_date and remove_course, which duplicate course.details.dialog_title, dialogs.DateContributeForm.add_date and course.item.remove_from_semester. The drawer now reuses the existing keys; only course_location and location_unavailable were kept.

Issues fixed in #872

Campus data re-downloaded on every window focus. CampusMapPage.tsx sets staleTime: 0 with refetchOnMount: "always" and refetchOnWindowFocus: "always", and data.ts fetches with cache: "no-store". main had staleTime: Infinity. Since the URL and query key already carry CAMPUS_MAP_DATA_CACHE_VERSION, this looks like leftover dev-time cache-busting. Effect: alt-tab away and back and the browser re-downloads and re-parses 218 KB, and because the parse yields fresh object identities, every useMemo in CampusWorld recomputes, all 112 building geometries are rebuilt, and the camera effect refires. Reverted to staleTime: Infinity and a plain fetch.

Roads and paths vanish when boundary is absent. LinearFeatures is called with clipToCampus hardcoded on for roads and paths, which sets stencilWrite + EqualStencilFunc with ref 1. If CampusClipMask renders null — which it does whenever data.boundary is undefined, a case normalizeCampusMapData explicitly allows — the stencil buffer stays 0 and every road and path fragment fails the test. Now gated on Boolean(data.boundary).

西院宿舍 doesn't match the legend. getBuildingColorCategory only treats as a dormitory, so the 15 curated 西院宿舍 parts render in the standard grey while the legend shows a blue dormitory swatch. Widened to /齋|宿舍/.

Overpass 200 with no elements. fetchOverpassData casts any OK response straight to OverpassResponse. A mirror returning 200 {} crashes at osm.elements.filter instead of falling through to the next endpoint. Added an Array.isArray(payload.elements) check before accepting.

type-check is red on arrival. apps/web's type-check now chains && bun run type-check:test, and that project fails immediately on pre-existing errors in timetableReconcile.test.ts (missing test/expect globals — those files don't import from bun:test) and syncedStorage.test.ts (MergeData<unknown> variance). CI doesn't run type-check, so nothing breaks, but the script never passes. I kept type-check as plain tsc --noEmit and left type-check:test as an opt-in — worth a separate PR to make those files typecheck, tsconfig.test.json is a good idea.

Left for a follow-up

The "Course Location" button can lead nowhere. getCampusMapHref returns a link for any venue that resolves to a known identity, without checking that the generated map actually contains a building with that identityId. Today CCcomputer-center and 普物實驗館physics-lab both produce a link, the button is enabled, and the map opens on the "not mapped yet" warning. Your own campusData.test.ts prints exactly these two as unmatched. It degrades gracefully so I didn't block on it, but either curating those two buildings into the data or having the helper check availability would close it.

getCampusFeatureNames hardcodes 湖泊 / Lake as the fallback for the one unnamed water feature (osm-way-257102746-0) rather than reading it from en.json / zh.json.

Verification

  • 140 tests pass across web, shared, map-data and api — same as the main baseline.
  • bun run --cwd apps/web type-check: 8 errors, byte-identical to main. No new type errors.
  • Browser: map renders, search → 台達館 focuses and opens the panel, ?building= and ?venue= deep links work, an unmapped venue shows the warning, labels/legend/trees/water/boundary/courtyard holes all render correctly.

Closing in favour of #872.

ImJustChew added a commit that referenced this pull request Sep 11, 2026
…871) (#872)

* fix: improve local web development setup

* feat(web): add interactive 3D campus map

* chore(web): rename interactive campus map app

* feat(map): label campus lakes

* feat(map): make all campus labels interactive

* fix(map): migrate cached water locations

* fix(map): filter features to NTHU campus boundary

* feat(map): number campus location labels

* fix(map): curate campus building coverage

* revert(map): restore uncropped campus data

* feat(map): add editable campus curation config

* feat(map): hardcode stable label numbers

* fix(map): refresh curated campus data

* Update campus map curation data: expand excluded list, add renamed locations, and define new groups for dormitories and faculty residences

* fix(map): harden production geometry checks

* feat(map): add campus environment layer

* feat(web): enhance campus map and curation

* feat(web): link timetable courses to campus map

* fix(map): address review findings on the campus map update

Follow-up fixes on top of #871, found by code review:

- Restore `staleTime: Infinity` and drop `cache: "no-store"` on the campus
  data query. The asset is already versioned through
  CAMPUS_MAP_DATA_CACHE_VERSION, so `staleTime: 0` +
  `refetchOnWindowFocus: "always"` + `no-store` re-downloaded and re-parsed
  218 KB on every window focus and rebuilt every building geometry and the
  camera tween with it.
- Only stencil-clip roads and paths when a boundary mask is actually drawn.
  With `clipToCampus` hardcoded on, map data without a `boundary` enabled the
  stencil test against an all-zero buffer and every road and path fragment
  was discarded.
- Treat 宿舍 as a dormitory alongside 齋 so the 15 西院宿舍 parts match the
  legend's dormitory swatch instead of rendering as generic buildings.
- Validate that an Overpass 200 response actually carries an `elements` array
  before accepting it, so a malformed reply falls through to the next mirror
  instead of crashing generation with a TypeError.
- Keep `type-check` as plain `tsc --noEmit`. Chaining the new
  `type-check:test` project made the command fail on pre-existing errors in
  timetableReconcile.test.ts and syncedStorage.test.ts; the project stays
  available as an opt-in script.

Conflict resolution against main also kept main's `bun test src` scripts
(reverting them to single-path globs would have undone #865) and reused the
existing course/date/remove dictionary keys instead of the duplicates the
branch added under timetable.course_actions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GvM2uNLLbgPyrp1HEHobtb

* fix(map): satisfy the SonarCloud reliability gate

Three bare `.sort()` calls on string arrays in the curation pipeline
(typescript:S2871) dropped New Code reliability to D. Give each an explicit
`localeCompare` comparator so the curation JSON serializes deterministically.

Also use `RegExp.test` instead of `String.match` for the dormitory name check,
since the result is only used as a boolean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GvM2uNLLbgPyrp1HEHobtb

---------

Co-authored-by: sj <shijie.jh@gmail.com>
Co-authored-by: Shi Jie Ng <142388278+SJieNg123@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@ImJustChew

Copy link
Copy Markdown
Member

Merged as #872 (commit ef14dc7) — your commits are in the history. Closing this one since the branch itself could not be merged (it predates #838, which already put the first version of the map on main).

Thanks for the work on this — the curation pipeline and the environment layer are a good addition. The two follow-ups from the review are still open if you want to pick them up: curating computer-center and physics-lab into the generated data so the timetable's Course Location button doesn't dead-end for those venues, and moving the 湖泊 / Lake fallback into the dictionaries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants