{"id":47628904,"url":"https://github.com/thejefflarson/mosaic","last_synced_at":"2026-04-17T10:11:41.165Z","repository":{"id":346091344,"uuid":"1188474123","full_name":"thejefflarson/mosaic","owner":"thejefflarson","description":"Infinite 2D spatial canvas for macOS where every window is a live terminal","archived":false,"fork":false,"pushed_at":"2026-03-30T05:47:25.000Z","size":67728,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-30T07:49:52.681Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thejefflarson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-22T05:53:36.000Z","updated_at":"2026-03-30T05:47:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/thejefflarson/mosaic","commit_stats":null,"previous_names":["thejefflarson/mosaic"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/thejefflarson/mosaic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thejefflarson%2Fmosaic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thejefflarson%2Fmosaic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thejefflarson%2Fmosaic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thejefflarson%2Fmosaic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thejefflarson","download_url":"https://codeload.github.com/thejefflarson/mosaic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thejefflarson%2Fmosaic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-01T23:04:24.787Z","updated_at":"2026-04-01T23:04:27.698Z","avatar_url":"https://github.com/thejefflarson.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"Docs/icon-concept-a.svg\" width=\"256\" alt=\"Mosaic icon\" /\u003e\n\n# Mosaic\n\n\u003c/div\u003e\n\nAn infinite 2D spatial canvas for macOS where real PTY-backed terminal windows can be freely panned, zoomed, dragged, and resized. Think of it as a whiteboard where every sticky note is a live shell.\n\nhttps://github.com/user-attachments/assets/6f503b39-5477-4ede-a528-04e4f09dc268\n\n**[Download the latest release](https://github.com/thejefflarson/mosaic/releases/latest)**\n\n\n## What it does\n\n- **Infinite canvas** — pan with two-finger scroll, zoom with pinch or scroll wheel, zoom anchored to cursor position\n- **Real terminals** — each window is a live PTY running your shell\n- **Freeform layout** — drag windows by their title bar, resize from any edge or corner\n- **Annotations** — text labels, sticky notes, arrows, freehand drawing, and images directly on the canvas\n- **Minimap** — always-visible overview in the corner; click or drag to jump\n- **Broadcast mode** — fan keystrokes out to all terminal windows simultaneously\n- **Themes** — built-in themes plus a full SwiftUI theme editor with export/import\n- **Workspace persistence** — layout, annotations, and scrollback history restored across launches\n\n## Requirements\n\n- macOS 14 (Sonoma) or later\n- Xcode 15 or later\n- [xcodegen](https://github.com/yonaskolb/XcodeGen): `brew install xcodegen`\n\n## Building\n\n```bash\nxcodegen generate\nopen Mosaic.xcodeproj\n# Cmd+R to run\n```\n\nOn first build, Xcode resolves the SwiftTerm SPM dependency automatically.\n\n## Running tests\n\n```bash\nxcodegen generate\nxcodebuild test -scheme MosaicTests -destination 'platform=macOS'\n```\n\n## Keyboard shortcuts\n\n| Key | Action |\n|-----|--------|\n| `V` | Pointer tool |\n| `T` | Terminal placement tool (click canvas to spawn) |\n| `L` | Text label |\n| `N` | Sticky note |\n| `A` | Arrow |\n| `P` | Pen / freehand |\n| `I` | Insert image |\n| `X` | Delete tool (click or drag a selection box) |\n| `Cmd+T` | New terminal (at default position) |\n| `Cmd+S` | Save workspace |\n| `Cmd+0` | Reset zoom to 100% |\n| `Cmd+F` | Fit all terminals in view |\n| `Cmd+Shift+B` | Toggle broadcast mode |\n| `Cmd+Arrow` | Focus nearest terminal in that direction |\n| Double-click canvas | Spawn terminal at cursor |\n| Right-click annotation | Delete |\n| `Cmd`+scroll | Force pan (overrides terminal scroll) |\n\n## AppleScript\n\nMosaic is scriptable. You can focus terminals by directory, open new ones, and query basic state:\n\n```applescript\n-- Focus the terminal whose working directory is ~/dev/myproject\nfocus terminal \"/Users/you/dev/myproject\" of application \"Mosaic\"\n\n-- Open a new terminal at a specific path\nopen terminal at \"/tmp\" of application \"Mosaic\"\n\n-- Read the active terminal's working directory\ntell application \"Mosaic\"\n    get working directory\nend tell\n\n-- Count open terminals\ntell application \"Mosaic\"\n    get terminal count\nend tell\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│  AppDelegate                                            │\n│  └─ CanvasViewController (coordinator)                  │\n│      ├─ CanvasView ──────── worldView (FlippedView)     │\n│      │   └─ bounds transform   ├─ TerminalWindowView(s) │\n│      │      (pan/zoom)         └─ AnnotationView(s)     │\n│      ├─ MinimapView (CVDisplayLink, ~60fps)             │\n│      ├─ ToolPaletteView (SwiftUI HUD)                   │\n│      └─ ThemeEditorViewController (SwiftUI panel)       │\n│                                                         │\n│  WorkspaceStore ──► ~/Library/Application Support/      │\n│                      Mosaic/workspace.json              │\n│                      Mosaic/Images/\u003cuuid\u003e.png           │\n└─────────────────────────────────────────────────────────┘\n```\n\nPure Swift + AppKit + [SwiftTerm](https://github.com/migueldeicaza/SwiftTerm). No Electron, no web runtime. SwiftUI is used for floating panels and HUDs where it adds value without complicating world-space coordinate math.\n\nSee `Docs/ADR/` for detailed rationale behind key decisions.\n\n## Project layout\n\n```\nMosaic/\n├── App/              # AppDelegate, menu bar\n├── Canvas/           # CanvasView, CanvasViewController, CanvasGeometry, FlippedView\n├── Terminal/         # TerminalWindowView, TitleBarView, ResizeHandleView, TerminalManager\n├── Annotations/      # AnnotationView subclasses, ToolPaletteView, CanvasTool\n├── Minimap/          # MinimapView\n├── Theming/          # Theme, ThemeEditorViewController (SwiftUI)\n├── Persistence/      # WorkspaceSnapshot (Codable), WorkspaceStore\n└── Utilities/        # Extensions (Comparable.clamped, CGRect center init)\n\nTests/                # Unit tests (MosaicTests target)\nDocs/ADR/             # Architecture Decision Records\n```\n\n## Persistence\n\n- **Workspace** auto-saves to `~/Library/Application Support/Mosaic/workspace.json` on a 5-second debounce; flushed synchronously on quit.\n- **Terminal scrollback** (up to 500 lines by default) is saved as plain text and restored dim/italic on next launch.\n- **Image annotations** are saved as PNGs in `~/Library/Application Support/Mosaic/Images/`.\n- Terminal PTY processes are always fresh on launch — only the working directory is restored.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthejefflarson%2Fmosaic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthejefflarson%2Fmosaic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthejefflarson%2Fmosaic/lists"}