尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Live: https://mybto.sg (the old address mybto.web.app redirects here)
Ranks every sale unit of the June 2026 BTO projects by each user's own importance weights.
| Type | Projects |
|---|---|
| Plus | Kebun Baru Breeze, Kebun Baru Ridge (Ang Mo Kio) |
| Prime | Berlayar Rise (Bukit Merah), Lakeview Cascadia (Bishan) |
| Standard | Sembawang Brook, Sembawang Portico (Sembawang), Woodgrove Acres (Woodlands) |
Stack: a static site on Firebase Hosting (public/, free Spark plan, no Cloud Functions, no sign-in) at https://mybto.sg (mybto.web.app redirects to it).
Rankings and shortlists are stored in a Google Sheet through a Google Apps Script web app (apps-script/, free). The Analytics page
reads combined results from the same web app. The browser knows the web app's address from public/js/config.js (SHEETS_URL).
pipeline/raw/real/, published by python3 pipeline/build_real_data.py --publish)The notes below describe the older sample pipeline.
public/data/units/*.json is generated by python3 pipeline/make_sample_data.py.
Berlayar Rise's unit list (blocks, storeys, unit numbers, flat types, 1,976 units) is real; every other attribute,
and all units of the other six projects, are placeholders.pipeline/raw/facilities_1st_storey.json, read off the HDB brochures); other facility values are placeholders.mscp_m, mscp_near = within 100 m) uses the real car park blocks and block numbers from the
brochure site plans, but the distances are by-eye estimates (about 10 m, 20 m for Sembawang Brook), in
pipeline/raw/mscp_distance.json (with the pixel positions used). wind_open (no block within 30 m on the SE to E side) is a
placeholder correlated with facing in the sample data; build_dataset.py computes it from site-plan stack positions.public/data/sample_submissions.json (420 sample users, npm run sample) is copied into the sheet's "Sample" tab by
importSample() and mixed into Analytics so the charts have something to show. Turn off by setting cell B1 of the "Settings" tab to FALSE.pipeline/build_dataset.py) builds the same JSON plus the Excel workbook
(tabs Plus / Prime / Standard) from the reconciled brochure extractions in pipeline/raw/./ ranking (same as /rank) · /shortlist · /archive/analytics (Analytics is archived: /analytics and /analysis redirect to /, the tab and button come back with ANALYTICS_ENABLED: true in public/js/config.js; ads are off with ADS_ENABLED: false) · /archive/home (old home page). /account, /archive/account and /archive/dashboard redirect to / (see firebase.json).
Inner pages are generated from one shell: edit pipeline/build_pages.py, then python3 pipeline/build_pages.py.
Images in public/img/ are artist's impressions from HDB's June 2026 BTO brochures (© HDB), credited in the footer.
mybto:uid). The last filters and weights per project stay in the browser (mybto:last:<project>).
The ad and the rewarded video are placeholders in public/js/ads.js (one place to plug in a real ad network).SHEETS_URL is set it says "Analytics will appear here soon."firebase.json sends a strict CSP and the usual security headers. Chart.js (archived Analytics only) loads with SRI. No Firebase JS runs on the site.robots.txt and sitemap.xml let search engines list the pages but not /data/. Steps to get into Google: docs/GOOGLE_INDEXING.md.apps-script/; re-paste and publish a new version to apply them.Google Analytics 4 (GA_ID in public/js/config.js, loader public/js/ga.js, live site only) counts visits and the actions rank, shortlist add/remove, share, legend and coffee click. See analytics.google.com.
Google AdSense Auto ads (ADSENSE_CLIENT in public/js/config.js, loader public/js/adsense.js, public/ads.txt, privacy policy at /privacy). Placement is controlled in the AdSense dashboard.
Follow apps-script/README.md. At the end you have an address ending in /exec. Put it in public/js/config.js as SHEETS_URL.
mybto-ce84f, set in .firebaserc; Hosting uses the extra site mybto (mybto.web.app, with the custom domain mybto.sg on top).mybto so the default address is https://mybto.web.app (otherwise change the name in the Apps Script SAMPLE_URL).npx firebase-tools login, then npx firebase-tools hosting:sites:create mybto --project mybto-ce84f (once), then npx firebase-tools deploy --only hosting:site.The old Vercel site and the old Firestore project are no longer used by the code.
npm install # no runtime dependencies; this only sets up the lockfile
npm run dev # http://localhost:3000, static site; SHEETS_URL in js/config.js decides where rankings go
npm run dev:fake # same, with a fake in-memory Google Sheet at /fake-sheets (what the browser test uses)
npm test # unit tests (scoring + analytics maths from apps-script/Analytics.js)
CHROMIUM=/opt/pw-browsers/chromium node test/e2e.browser.js # browser test of the full flow (needs Playwright)