Fork and go: fetch your starred repositories, build a Vue SPA, and deploy to GitHub Pages. Switch between list browsing and a Three.js cosmic star map. The UI supports Simplified Chinese / English (header toggle or ?lang=en).
For users who only want their own Star site without changing code:
- Fork this repository to your account.
- On the fork dialog, enable Copy the DEFAULT branch only so you do not copy the upstream
gh-pagesbranch. If you copy all branches, your first successful CI run will overwritegh-pagesanyway. - In the forked repo: Settings → Actions → General — allow Actions to run (org policies may apply).
- First deploy (required) — forking alone does not start CI; trigger it once yourself:
- Recommended: Actions → Build and Deploy My Stars → Run workflow → branch
main→ Run workflow, then wait for a green check (about 1–5 minutes; longer with many stars). - Alternatives: push any commit to
main(also triggers CI; see Automatic deployment below), or wait for the daily 00:00 UTC schedule (still run manually the first time).
- Recommended: Actions → Build and Deploy My Stars → Run workflow → branch
- After a successful workflow run, check Settings → Pages: source should be
gh-pagesbranch / root (set up bypeaceiris/actions-gh-pagesafter the first green run). - Open:
https://<your-username>.github.io/<repo-name>/(Pages may take another 1–2 minutes to go live).
CI uses github.repository_owner and the current repository name to fetch stars and build. You usually do not need to change scripts. Optionally edit config.json at the repo root for site title, default sort, etc.
| Trigger | Description |
|---|---|
push to main |
Runs only when generate.js, config.json, package*.json, web/**, or this workflow changes (README-only pushes do not trigger) |
| Daily 00:00 UTC | Scheduled sync of latest stars |
| Manual | Actions → Build and Deploy My Stars → Run workflow |
Pipeline: generate (GitHub API → stars.json + precomputed galaxy.json) → build:pages (Vue → web/dist) → push to gh-pages (not main).
- No deploy on fork alone: complete step 4 above (manual Run workflow or push) before your site shows your own stars.
mainhas no build artifacts:web/dist,web/public/stars.json,web/public/galaxy.json, andsite.jsonare gitignored.- If you forked upstream
gh-pages: Pages may briefly show the upstream site until your workflow succeeds; run CI once or deletegh-pageson your fork and redeploy. - Renaming the repo: CI updates
owner/repoNamein data and the Pages base path; changepageConfig.siteNameinconfig.jsonyourself if you want a new title.
After you add a custom domain under Settings → Pages, the site is usually served at the domain root (https://your-domain/), not https://<user>.github.io/<repo-name>/.
CI build:pages reads deployConfig.pagesBase in config.json for the asset prefix (Vite base). The app loads stars.json, site.json, and bundles under that prefix.
pagesBase |
URL you use | Notes |
|---|---|---|
"repo" (default) |
https://<user>.github.io/<repo-name>/ |
Prefix /<repo-name>/; default fork setup |
"root" |
Custom domain root https://your-domain/ |
Prefix /; use with a custom domain |
Impact on features: Filtering, UI languages, ?lang=en, star map view, and CI star fetching are unchanged. A mismatched pagesBase usually causes 404s for assets or JSON (blank page or endless loading).
Custom domain steps:
- Configure the domain and DNS under Settings → Pages (HTTPS via GitHub).
- Edit
config.json: set"deployConfig": { "pagesBase": "root", ... }. - Push to
mainor run the workflow to rebuild and deploy (DNS alone is not enough).
For the default *.github.io/<repo-name>/ URL, keep "pagesBase": "repo" — no other changes.
- Node.js 20+
- Git (to resolve
originand repo name) GITHUB_TOKENstrongly recommended for large star lists (~60 req/hour/IP unauthenticated vs ~5000/hour authenticated)
Create a GitHub Personal Access Token, then export it (use the block for your OS):
# macOS / Linux
export GITHUB_TOKEN=ghp_your_token# Windows PowerShell
$env:GITHUB_TOKEN="ghp_your_token"# Windows CMD
set GITHUB_TOKEN=ghp_your_tokenCross-platform note:
OWNER=xxx npm run ...works on macOS / Linux / Git Bash only. On PowerShell use$env:OWNER="xxx"; npm run ...; on CMD useset OWNER=xxx && npm run .... All env-var examples below list all three.
| Scenario | Behavior |
|---|---|
| Clone your fork | Username from origin ✅ |
| Clone upstream tool repo | Does not fetch upstream author’s stars; tries OWNER → GITHUB_TOKEN → gh auth login |
| CI / Actions | Uses github.repository_owner ✅ |
npm install
npm run devOpen http://localhost:4173/. dev runs generate then Vite.
The dev server listens on your LAN (host: true). The terminal prints a Network URL (e.g. http://192.168.x.x:4173/) for phones or other devices on the same Wi‑Fi (allow port 4173 in your firewall).
UI-only work (skip API fetch):
npm run dev:uiRequires existing web/public/stars.json (run npm run generate once first).
Override owner (optional):
# macOS / Linux / Git Bash
OWNER=your-username npm run generate
GITHUB_TOKEN=ghp_xxx npm run generate# Windows PowerShell
$env:OWNER="your-username"; npm run generate
$env:GITHUB_TOKEN="ghp_xxx"; npm run generate# Windows CMD
set OWNER=your-username && npm run generate
set GITHUB_TOKEN=ghp_xxx && npm run generateDev port 4173 (localhost + LAN). Stop it:
npm run dev:stop(macOS / Linux / Windows).
REPO_NAME is your GitHub repository name (e.g. after a fork you rename the repo to my-stars, use my-stars), not your GitHub username.
| Scenario | Who sets REPO_NAME |
|---|---|
| GitHub Actions | Automatically: github.event.repository.name |
Local build:pages / preview:pages |
Must match production; defaults to stars if unset |
With deployConfig.pagesBase set to "repo", the build uses /<REPO_NAME>/ as the asset prefix. That must match the repo segment in https://<user>.github.io/<repo-name>/. If you renamed the repo after forking, set it explicitly when testing locally:
# macOS / Linux / Git Bash
REPO_NAME=your-repo-name npm run build:pages
REPO_NAME=your-repo-name npm run preview:pages# Windows PowerShell
$env:REPO_NAME="your-repo-name"; npm run build:pages
$env:REPO_NAME="your-repo-name"; npm run preview:pages# Windows CMD
set REPO_NAME=your-repo-name && npm run build:pages
set REPO_NAME=your-repo-name && npm run preview:pagesnpm run preview (plain build) uses base=/ and does not need REPO_NAME. With pagesBase: "root" (custom domain), the prefix is / and repo name path does not apply.
| Command | Purpose |
|---|---|
npm run preview |
base=/ — local data and build |
npm run preview:pages |
base=/<REPO_NAME>/ (or pagesBase) — closer to GitHub Pages |
Both: generate + matching build + vite preview (port 4173). If your repo is not named stars, set REPO_NAME as above.
| Command | Description |
|---|---|
npm run dev |
Fetch stars + Vite (:4173, HMR) |
npm run dev:ui |
Vite only, no fetch |
npm run dev:stop |
Free port 4173 (cross-platform) |
npm run generate |
Write web/public/stars.json, galaxy.json, site.json |
npm run generate:galaxy |
Recompute galaxy.json from existing stars.json (no API fetch) |
npm run build |
Local build (base=/) |
npm run build:pages |
GitHub Pages build (base from pagesBase) |
npm run preview |
generate + build + preview |
npm run preview:pages |
generate + build:pages + preview |
GitHub Stars–like browsing; one stars.json; filtering in the browser:
| Feature | Description |
|---|---|
| Search | Repo name & description; #vue for exact topic filter (AND for multiple, e.g. #vue #typescript) |
| Type | All / Sources / Forks |
| Language | Sidebar list with counts |
| License | Filter by SPDX license |
| Starred year | Filter by year you starred |
| Sort | Recently starred / Recently active / Most stars |
| Virtual list | Smooth scrolling for thousands of items |
| Stats | Totals, language/license breakdown, etc. |
| View modes | List / cosmic star map (WebGL; star map disabled when WebGL is unavailable) |
Use the header List / Star map toggle. The map shares the same filtered set as the list (search, language, license, sort, etc.) and adds legend filters.
Spatial model
| Layer | Meaning |
|---|---|
| Language clusters | Repos grouped by language — each cluster acts as a “galaxy” |
| Topic rings / clouds | Popular topics within a language form rings or clouds |
| Virtual stars | One star per topic per repo; a placeholder star if the repo has no topics |
| Point size | Mapped from repo star count percentiles; brightness includes recency and other visual weights |
Layout is precomputed at generate time into galaxy.json and loaded on demand; if missing, the browser falls back to the same v3 runtime layout algorithm.
Interaction
| Action | Description |
|---|---|
| Left drag | Orbit |
Scroll / + - |
Zoom (eased) |
| Middle drag / pinch | Zoom |
| Right drag | Pan |
| Click a star | Fly in and open details |
| Hover | Show repo name and star count |
| Arrow keys | Nudge the view |
R |
Reset to default view |
| Auto-rotate toggle | Toolbar control for camera spin |
| Legend | Highlight by language or star tier (50k+ / 10k+ / 1k+ / <1k) |
| Focus | Fly to the first-starred repo or the repo in the detail panel |
| Expand | Fill the content area with the map (desktop) |
Detail panel: compact by default; expand for full info; Locate button (or L) flies to the current repo; Esc closes.
Note: while auto-rotate is on, motion freezes briefly on pointer down to improve click accuracy; moving the cursor over the canvas does not pause rotation.
- Header 中文 / EN toggle.
- URL:
?lang=enfor English; default Chinese unlessdefaultUiLocaleinconfig.jsonsays otherwise. - Star data is shared; UI locale does not duplicate
stars.json.
| Param | Description |
|---|---|
lang |
UI: en = English; omit = Chinese |
stars-q |
Search; #topic for topic filter |
stars-lang |
Programming language |
stars-license |
License |
stars-year |
Year starred |
stars-type |
sources / forks |
stars-sort |
recently_starred / recently_active / most_stars |
stars-view |
galaxy opens the star map view |
stars-focus |
Repo id to focus in the map (e.g. owner/repo) |
stars-galaxy-expand |
1 expands the map to fill the content area |
Example: ?stars-view=galaxy&stars-focus=vuejs/core&lang=en
| Stage | Approach |
|---|---|
| Data | Single stars.json fetch (~1–2MB for ~3k stars) |
| Star map layout | Precomputed in galaxy.json at build time; map chunk loaded async |
| List | @tanstack/vue-virtual — visible rows only |
| Star map | WebGL + Three.js; renders while visible; pauses when the tab is hidden |
| Filters | In-memory filter/sort; debounced search (searchDebounceMs) |
For very large lists, set pageConfig.maxItems in config.json or tune virtualRowHeight.
| Key | Description | Default |
|---|---|---|
pageConfig.siteName |
Site title (not auto-updated on rename) | Stars |
pageConfig.defaultUiLocale |
Default UI: zh-CN / en |
zh-CN |
pageConfig.defaultSort |
Default sort | recently_starred |
pageConfig.maxItems |
Max stars written (0 = no limit) |
0 |
pageConfig.showLanguage |
Show language on cards | true |
pageConfig.showStarsCount |
Show star count on cards | true |
pageConfig.showLicense |
Show license on cards | true |
pageConfig.virtualRowHeight |
Virtual list row height | 140 |
pageConfig.searchDebounceMs |
Search debounce (ms) | 300 |
pageConfig.toolRepoOwner / toolRepoName |
Footer link to tool repo | OXOYO / stars |
deployConfig.publishDir |
CI artifact dir on runner | web/dist |
deployConfig.forceOrphan |
Orphan gh-pages deploy |
true |
deployConfig.pagesBase |
Asset prefix: repo = /<repo-name>/; root = / (custom domain) |
repo |
After edits: local — generate / dev again; online — push to main or run the workflow manually.
.github/workflows/build.yml # Build & deploy
web/ # Vue 3 + Vite SPA
public/ # stars.json, galaxy.json, site.json (generated, not committed)
src/
components/ # List, star map, filters, stats UI
galaxy/ # Layout, motion, picking, zoom (Three.js)
composables/ # State, theme, i18n
generate.js # GitHub Star API → JSON
scripts/
compute-galaxy-layout.mjs # Star map layout precomputation
config.json # Page & deploy settings
package.json
main: source and config only; no committedweb/distor generated JSON.gh-pages: static site written by CI for GitHub Pages.deployConfig.publishDiris the upload folder on the CI runner, not a path committed onmain.