diff --git a/README.md b/README.md index 6f28bf0..c253c52 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,27 @@ -> [!CAUTION] -> This project is under construction and not ready for public use. Please check back in a few days! - # MouseTerm -Multitasking terminal for mice. +**Multitasking terminal for the mouse, tmux-compatible.** + +Run multiple terminals side-by-side, click to split, drag to resize. +When a pane stops outputting for two seconds, it's marked done — works +with any CLI tool, no plugins or config. + +![MouseTerm hero](website/src/assets/video-climb-blink-and-stare.webp) + +## Try it -- VSCode plugin or standalone desktop app -- tmux-compatible keybindings AND mouse -- alert system for notifying when a terminal task is done or waiting for user input +- **[Playground](https://mouseterm.com/playground)** — try in your browser, no install +- **[Demo videos and downloads](https://mouseterm.com)** — Mac, Windows, Linux +- **[Marketplace](https://marketplace.visualstudio.com/items?itemName=diffplug.mouseterm)** / **[Open VSX](https://open-vsx.org/extension/diffplug/mouseterm)** — VS Code extension (also works in Cursor, Windsurf, Antigravity) -Major URLs: -- [homepage with screen recordings](https://mouseterm.com) -- [download standalone app or VSCode plugins](https://mouseterm.com/#download) -- [playground and tutorial](https://mouseterm.com/playground) -- [production dependencies](https://mouseterm.com/dependencies) +## Features + +- **Automatic completion detection.** When a pane goes quiet for two seconds, it's marked done. Works with builds, AI agents, scripts, anything. +- **tmux-compatible keybindings.** Same prefix, same splits, same pane navigation. Muscle memory transfers. +- **Full mouse support.** Click to split, drag to resize, scroll to navigate. Or stay on the keyboard. +- **Copy-paste that works.** Click and drag selects text the way you'd expect, even in mouse-aware TUIs that normally swallow it as escape codes. Ctrl+C copies; killing the program is a separate gesture. +- **Sleep/wake panes.** Minimize a terminal to a compact status indicator. It keeps running and you can still see whether its task finished. +- **Dual distribution.** Standalone desktop app (Mac/Windows/Linux) or VS Code extension. ## Development @@ -23,8 +31,6 @@ The terminal is currently hosted by `node-pty`, but we plan on switching to a Ru ### Quickstart -Here are the key development loops: - ```sh pnpm install pnpm dev:website # vite hotreload at http://localhost:5173/playground @@ -54,3 +60,5 @@ This project was built with a combination of Claude, Codex, and Devin. Recommend ## License [FSL-1.1-MIT](LICENSE) — Copyright 2026 DiffPlug LLC + +[Production dependencies](https://mouseterm.com/dependencies) diff --git a/website/src/assets/phone-mockup.webp b/website/src/assets/phone-mockup.webp new file mode 100644 index 0000000..17a9136 Binary files /dev/null and b/website/src/assets/phone-mockup.webp differ diff --git a/website/src/index.css b/website/src/index.css index 7e68def..72d6989 100644 --- a/website/src/index.css +++ b/website/src/index.css @@ -14,6 +14,13 @@ html { color: var(--color-text); font-family: var(--font-body); font-kerning: normal; + scroll-padding-top: 4rem; /* matches SiteHeader h-16 on mobile */ +} + +@media (min-width: 768px) { + html { + scroll-padding-top: 5rem; /* matches SiteHeader h-20 on desktop (≥ md) */ + } } /* Override lib's terminal-app styles (body overflow:hidden, #root height:100vh, diff --git a/website/src/pages/Home.tsx b/website/src/pages/Home.tsx index f36ef89..1dad4d0 100644 --- a/website/src/pages/Home.tsx +++ b/website/src/pages/Home.tsx @@ -9,7 +9,7 @@ import { TerminalIcon, WindowsLogoIcon, } from "@phosphor-icons/react"; -import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type MouseEventHandler, type ReactNode } from "react"; +import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type FormEvent, type MouseEventHandler, type ReactNode } from "react"; import SiteHeader from "../components/SiteHeader"; import posterUrl from "../assets/video-climb-blink-and-stare.webp"; import videoUrl from "../assets/video-climb-blink-and-stare.mp4"; @@ -18,6 +18,7 @@ import copyPasteVideoUrl from "../assets/video-copy-paste.mp4"; import tmuxVideoUrl from "../assets/video-tmux.mp4"; import visualStudioIconUrl from "../assets/visual-studio-icon.svg"; import tinyIconUrl from "../assets/icon-tiny-dark.png"; +import phoneMockupUrl from "../assets/phone-mockup.webp"; import standaloneLatest from "@standalone-latest"; export { Home as Component }; @@ -37,6 +38,9 @@ const HEADER_REVEAL_LEAD = 0.04; const UNPIN_THRESHOLD = 0.8; const HERO_VIDEO_FPS = 120; +/** Vertical padding applied to all content sections after the hero. */ +const SECTION_PY = "py-8"; + /** Clamp a value to 0–1. */ const clamp01 = (v: number) => Math.min(1, Math.max(0, v)); const useClientLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; @@ -243,6 +247,89 @@ function DownloadGroupHeader({ ); } +const EMAIL_REGEX = + /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; + +function NotifySignupForm() { + const [email, setEmail] = useState(""); + const [loading, setLoading] = useState(false); + const [success, setSuccess] = useState(false); + const [message, setMessage] = useState(""); + + async function handleSubmit(e: FormEvent) { + e.preventDefault(); + if (loading) return; + + if (!EMAIL_REGEX.test(email)) { + setMessage("Please enter a valid email"); + return; + } + + setLoading(true); + setMessage(""); + + try { + const response = await fetch("https://substackapi.com/api/subscribe", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + email, + domain: "https://nedshed.dev/", + }), + }); + const data = await response.json(); + + if (data.errors) { + setMessage(data.errors[0].msg); + } else if (data.requires_confirmation) { + setSuccess(true); + } + } catch { + setMessage("Something went wrong. Please try again."); + } finally { + setLoading(false); + } + } + + if (success) { + return ( +

+ Thanks — check your email to confirm your subscription. +

+ ); + } + + return ( +
+
+ setEmail(e.target.value)} + placeholder="you@example.com" + required + disabled={loading} + aria-label="Email address" + className="min-h-12 w-full rounded-md border border-[var(--color-text)]/20 bg-[var(--color-bg)] px-4 py-3 text-base text-[var(--color-text)] placeholder:opacity-40 focus:border-[var(--color-caramel)] focus:outline-none disabled:opacity-50 sm:flex-1" + /> + +
+ {message && ( +

+ {message} +

+ )} +
+ ); +} + function Home() { const videoRef = useRef(null); const posterRef = useRef(null); @@ -672,7 +759,7 @@ function Home() { {/* ── Content sections — pulled up to appear as video starts scrolling ── */}
-
+

Stop watching terminals spin

MouseTerm tracks activity the same way you do — visual motion. When a @@ -687,7 +774,7 @@ function Home() {

{/* Section 2: text left, image right */} -
+

Copy paste like you meant

@@ -705,7 +792,7 @@ function Home() {

{/* Section 3: image left, text right */} -
+

Soft as a mouse, sharp as tmux

@@ -722,7 +809,7 @@ function Home() {
-
+

Get MouseTerm

The multitasking terminal for mice.

+
+ MouseTerm Playground running on a phone +
+

+ Take one for the road +

+

+ Coming next: Roam. Pair a + terminal session to your phone over WebRTC and take a stroll, the MouseTerm alert + system will buzz you if there's anything to do. A hosted auto-pairing service comes + later — just leave and keep working, no "I'm walking away" dance. +

+

+ Subscribe below to nedshed.dev — my dev log. Roam launches there first. When the hosted service is ready, we'll do discounts for early adopters, so don't miss out! +

+ +
+
+