A fast, client-side ASCII project structure generator. Scan any local folder or public GitHub repo and get a clean, copyable directory tree with collapsible directories, configurable excludes, and zero server uploads.
- File Upload mode — select any local project folder; the tree is built entirely in the browser, nothing is sent anywhere
- GitHub Repo URL mode — paste any public GitHub repo URL and fetch its full recursive file tree via the GitHub REST API in a single request
- Always-excluded dirs —
node_modules,.next,dist,build,.git,.turbo,.vercel,out,.cacheare stripped automatically - Soft excludes — optionally toggle
coverage,tmp,logs,.DS_Store,*.log - Collapse / expand directories — click individual dirs or use expand all / collapse all, grouped by depth level
- Copy to clipboard — one click to copy the full ASCII tree output
- Next.js 16 (App Router)
- React with
useTransitionfor non-blocking tree builds - TailwindCSS v4
- GitHub REST API (
/git/trees?recursive=1), no auth required for public repos
- Node.js 18+
- pnpm
pnpm installpnpm devOpen http://localhost:3000 in your browser.
pnpm build
pnpm start- Click the File Upload tab
- Click the drop zone and select a project folder
- Use the Additional Excludes toggles to filter out noise
- Click directories in the Collapse Directories panel to fold them in the output
- Hit copy to grab the ASCII tree
- Click the GitHub Repo URL tab
- Paste a public GitHub repo URL — any of these formats work:
https://github.com/owner/repo https://github.com/owner/repo/tree/main https://github.com/owner/repo/tree/my-branch - Click Scan Repo
- Collapse, filter, and copy as normal
Note: The GitHub REST API allows 60 unauthenticated requests per hour per IP. Repos with 100k+ files may be truncated by GitHub's API — a warning will appear if this happens. Private repos are not supported.
.
├── app/
│ ├── globals.css # TailwindCSS v4 theme + component styles
│ ├── layout.tsx # Root layout, fonts
│ └── page.tsx # Entry page
└── components/
└── TreeGenerator.tsx # Main component — all logic lives here
Both modes share a single buildTreeFromPaths(paths: string[], softExcludes) function that takes a flat array of file path strings and assembles the nested tree structure.
- File Upload — converts the browser
FileList(viawebkitRelativePath) into path strings, then callsbuildTreeFromPaths - GitHub mode — calls
GET /repos/{owner}/{repo}/git/trees/{branch}?recursive=1, extracts thepathfield from each blob entry, then callsbuildTreeFromPathswith the same result
Tree rendering, collapse state, excludes, and copy all operate identically regardless of source.
MIT