Skip to content

Commit 00686f0

Browse files
committed
Initial project setup
0 parents  commit 00686f0

33 files changed

Lines changed: 7714 additions & 0 deletions

.github/workflows/deploy.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Deploy Next.js site to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Node
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: "20"
28+
cache: npm
29+
30+
- name: Restore cache
31+
uses: actions/cache@v4
32+
with:
33+
path: |
34+
.next/cache
35+
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
36+
restore-keys: |
37+
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
38+
39+
- name: Install dependencies
40+
run: npm ci
41+
42+
- name: Build with Next.js
43+
run: npm run build
44+
45+
- name: Upload artifact
46+
uses: actions/upload-pages-artifact@v3
47+
with:
48+
path: ./out
49+
50+
deploy:
51+
environment:
52+
name: github-pages
53+
url: ${{ steps.deployment.outputs.page_url }}
54+
runs-on: ubuntu-latest
55+
needs: build
56+
steps:
57+
- name: Deploy to GitHub Pages
58+
id: deployment
59+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
.next
3+
out
4+
.DS_Store
5+
*.log
6+
.env*
7+
!.env.example
8+
DESIGN.md
9+
EDITOR.md

README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<div align="center">
2+
<br />
3+
<img src="public/logo.png" alt="editss" width="100" />
4+
<br /><br />
5+
6+
<h3><b>editss</b></h3>
7+
8+
<p><i>Drop it. Mark it. Ship it.</i></p>
9+
10+
<br />
11+
12+
<a href="https://edit-studio.github.io/editss">
13+
<img src="https://img.shields.io/badge/try_it_live-edit--studio.github.io-1d4c4a?style=flat-square" alt="Live Demo" />
14+
</a>
15+
&nbsp;
16+
<img src="https://img.shields.io/badge/100%25-local--first-333?style=flat-square" alt="Local First" />
17+
&nbsp;
18+
<img src="https://img.shields.io/badge/zero-uploads-333?style=flat-square" alt="Zero Uploads" />
19+
</div>
20+
21+
<br />
22+
23+
---
24+
25+
<br />
26+
27+
### The fastest way to annotate a screenshot.
28+
29+
**editss** is a browser-native screenshot editor built for people who value their time. No sign-ups, no file uploads, no Electron bloat — just an instant canvas that runs entirely in your browser's memory.
30+
31+
Paste a screenshot, draw an arrow, blur a secret, and hit save. The whole flow takes seconds, not minutes.
32+
33+
<br />
34+
35+
## Why editss?
36+
37+
Most screenshot tools are either too simple (basic crop & draw) or too complex (full image editors with 200 features you'll never use). **editss** sits right in the sweet spot:
38+
39+
- **Instant start.** Paste from clipboard (`⌘V`) or drag a file in. No "File → Open" dialogs.
40+
- **Professional tools.** Arrows, rectangles, ellipses, text, freehand pen, chat bubbles, numbered counters, blur, highlight, and spotlight — everything you actually need.
41+
- **Calm, focused design.** A restrained `parchment & ink` palette keeps the UI out of your way.
42+
- **Full history.** Unlimited undo/redo with `⌘Z` / `⇧⌘Z`. Duplicate objects with `⌘D`.
43+
- **One-click export.** `⌘S` downloads a PNG. `⌘C` copies to clipboard. Done.
44+
- **Completely local.** Your images never leave the browser tab. Zero servers, zero tracking.
45+
46+
<br />
47+
48+
## Keyboard Shortcuts
49+
50+
editss is designed to be driven entirely by keyboard for maximum speed:
51+
52+
| Shortcut | Action |
53+
| :--- | :--- |
54+
| `⌘V` | Paste image from clipboard |
55+
| `⌘C` | Copy annotated image to clipboard |
56+
| `⌘S` | Download as PNG |
57+
| `⌘Z` | Undo |
58+
| `⇧⌘Z` | Redo |
59+
| `⌘D` | Duplicate selected object |
60+
| `Backspace` | Delete selected |
61+
| `Space` (hold) | Pan canvas |
62+
| `Shift` (hold) | Constrain proportions |
63+
64+
<br />
65+
66+
## Tech Stack
67+
68+
| Layer | Technology |
69+
| :--- | :--- |
70+
| Framework | Next.js 15 (Static Export) |
71+
| UI | React 19, Framer Motion |
72+
| State | Zustand |
73+
| Styling | Tailwind CSS 4 |
74+
| Rendering | Canvas API, html2canvas-pro |
75+
| Hosting | GitHub Pages |
76+
77+
<br />
78+
79+
## Getting Started
80+
81+
```bash
82+
git clone https://github.com/edit-studio/editss.git
83+
cd editss
84+
npm install
85+
npm run dev
86+
```
87+
88+
Open `http://localhost:3000/editss` and start editing.
89+
90+
<br />
91+
92+
## Building for Production
93+
94+
```bash
95+
npm run build
96+
```
97+
98+
Generates a fully static bundle in `out/` — deployable to GitHub Pages, Vercel, Netlify, or any static host.
99+
100+
<br />
101+
102+
---
103+
104+
<div align="center">
105+
<br />
106+
<sub>Part of the <a href="https://github.com/edit-studio"><b>edit-studio</b></a> ecosystem — frictionless tools for the modern web.</sub>
107+
<br /><br />
108+
</div>

app/editor/page.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Topbar } from "@/components/editor/Topbar";
2+
import { Toolbar } from "@/components/editor/Toolbar";
3+
import { Canvas } from "@/components/editor/Canvas";
4+
import { RightPanel } from "@/components/editor/RightPanel";
5+
import { ZoomControl } from "@/components/editor/ZoomControl";
6+
import { KeyboardShortcuts } from "@/components/editor/KeyboardShortcuts";
7+
8+
export default function EditorPage() {
9+
return (
10+
<div className="h-screen w-screen flex flex-col bg-parchment">
11+
<KeyboardShortcuts />
12+
<Topbar />
13+
<div className="flex-1 flex overflow-hidden relative">
14+
<div className="flex-1 relative flex">
15+
<Toolbar />
16+
<Canvas />
17+
<ZoomControl />
18+
</div>
19+
<RightPanel />
20+
</div>
21+
</div>
22+
);
23+
}

app/globals.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
@import "tailwindcss";
2+
3+
@theme {
4+
/* Colors */
5+
--color-parchment: #fffdf8;
6+
--color-ink-black: #0a0a0a;
7+
--color-slate-gray: #474747;
8+
--color-ash-gray: #8c8c8c;
9+
--color-whisper-border: #e5e5e5;
10+
--color-ghost-border: #d1d1d1;
11+
--color-burnt-umber: #512906;
12+
--color-blue-violet: #242d64;
13+
--color-forest-green: #0c3b1a;
14+
--color-crimson-blush: #5e0831;
15+
--color-goldenrod: #ffc934;
16+
--color-claude-orange: #d97757;
17+
--color-petrol: #1d4c4a;
18+
19+
/* Editor surfaces */
20+
--color-canvas-bg: #fafaf7;
21+
--color-canvas-grid: #ececea;
22+
--color-toolbar-bg: #fffdf8;
23+
--color-tool-hover: #f4f1ea;
24+
--color-subtle-card: #f9f9f9;
25+
--color-accent-block: #fef5de;
26+
27+
/* Typography */
28+
--font-iowanold: "Iowan Old Style", "Iowan Old", Georgia, "Times New Roman",
29+
serif;
30+
--font-suisseintl: var(--font-inter), ui-sans-serif, system-ui, -apple-system,
31+
BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
32+
33+
/* Annotation fonts (Google Fonts via next/font) */
34+
--font-anno-serif: "Iowan Old Style", "Iowan Old", Georgia, "Times New Roman",
35+
serif;
36+
--font-anno-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
37+
--font-anno-caveat: var(--font-caveat), "Brush Script MT", cursive;
38+
--font-anno-hand: var(--font-patrick-hand), "Comic Sans MS", cursive;
39+
--font-anno-marker: var(--font-permanent-marker), "Marker Felt", sans-serif;
40+
--font-anno-mono: var(--font-jetbrains-mono), ui-monospace, "Menlo",
41+
monospace;
42+
43+
/* Type scale */
44+
--text-body-sm: 14px;
45+
--text-body: 16px;
46+
--text-subheading: 20px;
47+
--text-heading-sm: 32px;
48+
--text-heading: 42px;
49+
--text-display: 48px;
50+
51+
/* Radius */
52+
--radius-sm: 8px;
53+
--radius-md: 10px;
54+
--radius-lg: 14px;
55+
56+
/* Shadows */
57+
--shadow-toolbar: 0 4px 16px rgba(10, 10, 10, 0.04);
58+
--shadow-object: 0 8px 24px rgba(10, 10, 10, 0.06);
59+
--shadow-object-hover: 0 12px 32px rgba(10, 10, 10, 0.08);
60+
--shadow-menu: 0 8px 24px rgba(10, 10, 10, 0.08);
61+
}
62+
63+
@layer base {
64+
html,
65+
body {
66+
background: var(--color-parchment);
67+
color: var(--color-ink-black);
68+
font-family: var(--font-suisseintl);
69+
font-size: var(--text-body);
70+
line-height: 1.5;
71+
-webkit-font-smoothing: antialiased;
72+
-moz-osx-font-smoothing: grayscale;
73+
}
74+
75+
body {
76+
overflow: hidden;
77+
}
78+
79+
::selection {
80+
background: #fef5de;
81+
color: var(--color-ink-black);
82+
}
83+
}
84+
85+
@utility font-serif {
86+
font-family: var(--font-iowanold);
87+
font-feature-settings: "liga", "kern";
88+
}
89+
90+
@utility canvas-grid {
91+
background-color: var(--color-canvas-bg);
92+
background-image: radial-gradient(
93+
circle,
94+
var(--color-canvas-grid) 1px,
95+
transparent 1px
96+
);
97+
background-size: 24px 24px;
98+
background-position: 0 0;
99+
}
100+
101+
@utility toolbar-surface {
102+
background: var(--color-toolbar-bg);
103+
border: 1px solid var(--color-whisper-border);
104+
box-shadow: var(--shadow-toolbar);
105+
}
106+
107+
@utility ease-calm {
108+
transition-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
109+
}
110+
111+
/* Scrollbar — restrained */
112+
::-webkit-scrollbar {
113+
width: 10px;
114+
height: 10px;
115+
}
116+
::-webkit-scrollbar-track {
117+
background: transparent;
118+
}
119+
::-webkit-scrollbar-thumb {
120+
background: var(--color-whisper-border);
121+
border-radius: 999px;
122+
border: 2px solid var(--color-parchment);
123+
}
124+
::-webkit-scrollbar-thumb:hover {
125+
background: var(--color-ghost-border);
126+
}

app/layout.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { Metadata } from "next";
2+
import {
3+
Caveat,
4+
Patrick_Hand,
5+
Permanent_Marker,
6+
JetBrains_Mono,
7+
Inter,
8+
} from "next/font/google";
9+
import "./globals.css";
10+
11+
const inter = Inter({
12+
subsets: ["latin"],
13+
variable: "--font-inter",
14+
});
15+
const caveat = Caveat({
16+
subsets: ["latin"],
17+
variable: "--font-caveat",
18+
});
19+
const patrickHand = Patrick_Hand({
20+
subsets: ["latin"],
21+
weight: "400",
22+
variable: "--font-patrick-hand",
23+
});
24+
const permanentMarker = Permanent_Marker({
25+
subsets: ["latin"],
26+
weight: "400",
27+
variable: "--font-permanent-marker",
28+
});
29+
const jetbrainsMono = JetBrains_Mono({
30+
subsets: ["latin"],
31+
variable: "--font-jetbrains-mono",
32+
});
33+
34+
export const metadata: Metadata = {
35+
title: "editss — screenshot editor",
36+
description: "edit screenshots in seconds. ink on parchment.",
37+
};
38+
39+
export default function RootLayout({
40+
children,
41+
}: {
42+
children: React.ReactNode;
43+
}) {
44+
return (
45+
<html
46+
lang="en"
47+
className={`${inter.variable} ${caveat.variable} ${patrickHand.variable} ${permanentMarker.variable} ${jetbrainsMono.variable}`}
48+
>
49+
<body>{children}</body>
50+
</html>
51+
);
52+
}

0 commit comments

Comments
 (0)