Launch AutoBank site with Serial Console theme and scroll hourglass logo.
- AutoBank branding, phosphor-green terminal aesthetic - Five normalized logo frames that advance on scroll - Logo build scripts and design exploration docs under docs/
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.DS_Store
|
||||||
|
*.log
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Local preview / editor
|
||||||
|
.cursor/
|
||||||
57
README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# AutoBank
|
||||||
|
|
||||||
|
Static landing page for **AutoBank** — automation consulting by Ilia Dobkin (scripts, n8n/Zapier/Make, CI/CD, webhooks, AI integrations).
|
||||||
|
|
||||||
|
**Live site:** [auto.levkin.ca](https://auto.levkin.ca)
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- `index.html` — single page
|
||||||
|
- `styles.css` — Serial Console theme (phosphor green on black)
|
||||||
|
- `assets/logos/` — hourglass favicon + scroll-driven header logo (`*-64.png`)
|
||||||
|
|
||||||
|
No build step for deploy. Plain HTML/CSS.
|
||||||
|
|
||||||
|
## Local preview
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m http.server 8080
|
||||||
|
# http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logo tooling (optional)
|
||||||
|
|
||||||
|
Requires Node 18+.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run logos:normalize # source PNGs → assets/logos/*-64.png & *-128.png
|
||||||
|
```
|
||||||
|
|
||||||
|
Source art: `assets/logos/source/`. Design pickers (not deployed): `docs/brand-names.html`, `docs/style-directions.html`.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
Publish the repo root as static files (nginx `root`, Gitea pages, etc.).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
| What | URL |
|
||||||
|
|------|-----|
|
||||||
|
| Book a call | [cal.levkin.ca/ilia/consult](https://cal.levkin.ca/ilia/consult) |
|
||||||
|
| Email | [ilia@levkine.ca](mailto:ilia@levkine.ca) |
|
||||||
|
| LinkedIn | [linkedin.com/in/ilia-dobkin-8263343](https://www.linkedin.com/in/ilia-dobkin-8263343/) |
|
||||||
|
| Git | [git.levkin.ca](https://git.levkin.ca) |
|
||||||
|
|
||||||
|
## Edit
|
||||||
|
|
||||||
|
| What | Where |
|
||||||
|
|------|--------|
|
||||||
|
| Copy / sections | `index.html` |
|
||||||
|
| Theme colors | `styles.css` (`:root`) |
|
||||||
|
| Logo frames | `assets/logos/source/` then `npm run logos:normalize` |
|
||||||
|
| Booking URL | `cal.levkin.ca` in `index.html` |
|
||||||
BIN
assets/logos/00-full-128.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/logos/00-full-64.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
assets/logos/01-25pct-128.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
assets/logos/01-25pct-64.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
assets/logos/02-15pct-128.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
assets/logos/02-15pct-64.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
assets/logos/03-3grains-128.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
assets/logos/03-3grains-64.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
assets/logos/04-1grain-128.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
assets/logos/04-1grain-64.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
27
assets/logos/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Hourglass logo frames
|
||||||
|
|
||||||
|
Scroll order (top → bottom of page): sand depletes as time “runs out.”
|
||||||
|
|
||||||
|
| File | Step |
|
||||||
|
|------|------|
|
||||||
|
| `00-full-64.png` | Hero — fullest |
|
||||||
|
| `01-25pct-64.png` | ~25% scroll |
|
||||||
|
| `02-15pct-64.png` | ~50% |
|
||||||
|
| `03-3grains-64.png` | ~75% |
|
||||||
|
| `04-1grain-64.png` | Footer — one grain |
|
||||||
|
|
||||||
|
`*-128.png` are retina variants. Source art lives in `source/`.
|
||||||
|
|
||||||
|
## Regenerate web sizes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run logos:normalize
|
||||||
|
```
|
||||||
|
|
||||||
|
After editing the full frame draft:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node scripts/match-full-brightness.mjs path/to/draft.png
|
||||||
|
npm run logos:normalize
|
||||||
|
```
|
||||||
11
assets/logos/source/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Logo source art (not served on the site)
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|------|------|
|
||||||
|
| `hourglass-mint-full.png` | Frame 0 — matched to 25% brightness |
|
||||||
|
| `hourglass-mint-25pct.png` | Frame 1 — style reference |
|
||||||
|
| `hourglass-mint-15pct.png` | Frame 2 |
|
||||||
|
| `hourglass-mint-3grains.png` | Frame 3 |
|
||||||
|
| `hourglass-mint-1grain.png` | Frame 4 |
|
||||||
|
|
||||||
|
Run `npm run logos:normalize` from repo root to rebuild `../00-*-64.png` etc.
|
||||||
BIN
assets/logos/source/hourglass-mint-15pct.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/logos/source/hourglass-mint-1grain.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/logos/source/hourglass-mint-25pct.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/logos/source/hourglass-mint-3grains.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/logos/source/hourglass-mint-full.png
Normal file
|
After Width: | Height: | Size: 472 KiB |
8
docs/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Design exploration (local only)
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| [brand-names.html](brand-names.html) | Brand name brainstorm picker |
|
||||||
|
| [style-directions.html](style-directions.html) | Visual style brainstorm picker |
|
||||||
|
|
||||||
|
Open in a browser; not deployed to production.
|
||||||
807
docs/brand-names.html
Normal file
@ -0,0 +1,807 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Brand name & logo options — 40 picks</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=IBM+Plex+Mono:wght@400;500&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #0c0f14;
|
||||||
|
--surface: #151922;
|
||||||
|
--surface-2: #1c2230;
|
||||||
|
--line: #2a3347;
|
||||||
|
--ink: #eef1f6;
|
||||||
|
--muted: #8b95a8;
|
||||||
|
--accent: #6ee7b7;
|
||||||
|
--accent-dim: rgba(110, 231, 183, 0.12);
|
||||||
|
--warn: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "DM Sans", system-ui, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--ink);
|
||||||
|
line-height: 1.5;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 48px 24px 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--accent);
|
||||||
|
margin: 0 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(28px, 4vw, 40px);
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lede {
|
||||||
|
max-width: 62ch;
|
||||||
|
color: var(--muted);
|
||||||
|
margin: 0 0 20px;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-left: 3px solid var(--warn);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 14px 18px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
max-width: 72ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note strong {
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
margin: 28px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pick-label {
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pick-value {
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--surface);
|
||||||
|
color: var(--ink);
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: border-color 0.15s, background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
position: relative;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 2px solid var(--line);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 22px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s, transform 0.15s, box-shadow 0.2s;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option:hover {
|
||||||
|
border-color: #3d4a66;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.is-picked {
|
||||||
|
border-color: var(--accent);
|
||||||
|
box-shadow: 0 0 0 1px var(--accent), 0 20px 40px -20px rgba(110, 231, 183, 0.25);
|
||||||
|
background: linear-gradient(180deg, rgba(110, 231, 183, 0.06) 0%, var(--surface) 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-num {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 14px;
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--muted);
|
||||||
|
background: var(--surface-2);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.is-picked .option-num {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #0c0f14;
|
||||||
|
border-color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-mark {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-name {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-name .sub {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--muted);
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--ink);
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vibe {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vibe span {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--surface-2);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pros-cons {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--muted);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pros-cons strong {
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-old {
|
||||||
|
margin-top: 48px;
|
||||||
|
padding-top: 32px;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-old h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.old-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px dashed #4a3f55;
|
||||||
|
border-radius: 12px;
|
||||||
|
opacity: 0.75;
|
||||||
|
max-width: 420px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.old-card .brand-name {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.old-card p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-label {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--muted);
|
||||||
|
margin: 8px 0 0;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-label:first-of-type {
|
||||||
|
border-top: none;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
<header>
|
||||||
|
<p class="eyebrow">Brand brainstorm</p>
|
||||||
|
<h1>40 name & logo directions</h1>
|
||||||
|
<p class="lede">
|
||||||
|
Round 4 is all <strong>hourglass logos</strong> — time, minutes, payback, sand running down while
|
||||||
|
automation runs. Click a card to pick.
|
||||||
|
</p>
|
||||||
|
<p class="note">
|
||||||
|
<strong>Why iAutomate feels off:</strong> The “i” prefix reads as Apple cosplay circa 2008. “Automate”
|
||||||
|
is generic — half the industry uses it. These alternatives aim for memorable, credible, and easy to say on
|
||||||
|
a call.
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="toolbar">
|
||||||
|
<span class="pick-label">Your pick: <span class="pick-value" id="pick-display">none yet</span></span>
|
||||||
|
<button class="btn" type="button" id="clear-pick">Clear</button>
|
||||||
|
<button class="btn" type="button" id="copy-pick">Copy choice</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid" id="options"></div>
|
||||||
|
|
||||||
|
<div class="vs-old">
|
||||||
|
<h2>For comparison — current name</h2>
|
||||||
|
<div class="old-card">
|
||||||
|
<svg class="brand-mark" width="44" height="44" viewBox="0 0 32 32" fill="none" aria-hidden="true">
|
||||||
|
<rect width="32" height="32" rx="8" fill="#151922" />
|
||||||
|
<circle cx="16" cy="7.5" r="3.25" fill="#6ee7b7" />
|
||||||
|
<path d="M16 11v4.5" stroke="#6ee7b7" stroke-width="2.5" stroke-linecap="round" />
|
||||||
|
<circle cx="16" cy="18" r="2.25" fill="#6ee7b7" />
|
||||||
|
<path d="M16 20.25 9.5 26.5M16 20.25v5M16 20.25 22.5 26.5" stroke="#6ee7b7" stroke-width="2" stroke-linecap="round" />
|
||||||
|
<circle cx="9.5" cy="26.5" r="2" fill="#6ee7b7" opacity="0.85" />
|
||||||
|
<circle cx="16" cy="28" r="2" fill="#6ee7b7" />
|
||||||
|
<circle cx="22.5" cy="26.5" r="2" fill="#6ee7b7" opacity="0.85" />
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<div class="brand-name">iAutomate</div>
|
||||||
|
<p>Generic + dated Apple vibe. Logo reads as “org chart” not “automation.”</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Runloop",
|
||||||
|
sub: "runloop.dev",
|
||||||
|
tagline: "Automation that keeps running.",
|
||||||
|
vibe: ["dev-native", "CLI energy", "reliable"],
|
||||||
|
note: "Developers instantly get it. Strong for scripts, cron, CI/CD. Slightly niche for non-technical buyers — but your site explains it.",
|
||||||
|
color: "#6ee7b7",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 22a8 8 0 0 1 8-8" stroke="#6ee7b7" stroke-width="2.5" stroke-linecap="round"/><path d="M30 22a8 8 0 0 1-8 8" stroke="#6ee7b7" stroke-width="2.5" stroke-linecap="round"/><path d="M22 14v4M22 26v4" stroke="#6ee7b7" stroke-width="2" stroke-linecap="round" opacity="0.5"/><circle cx="22" cy="22" r="3" fill="#6ee7b7"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Relay",
|
||||||
|
sub: "relay automation",
|
||||||
|
tagline: "Hand off the work. Keep the outcome.",
|
||||||
|
vibe: ["minimal", "clean", "handoff"],
|
||||||
|
note: "Short, professional, easy domain hunting. Implies connecting systems and passing data. Logo is an arrow-through-circle — motion without clutter.",
|
||||||
|
color: "#60a5fa",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><circle cx="22" cy="22" r="10" stroke="#60a5fa" stroke-width="2"/><path d="M16 22h12M24 18l4 4-4 4" stroke="#60a5fa" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "Flowcraft",
|
||||||
|
sub: "flowcraft studio",
|
||||||
|
tagline: "Crafted workflows that don't break.",
|
||||||
|
vibe: ["artisan", "premium", "consultancy"],
|
||||||
|
note: "Feels like a studio, not a SaaS. Good if you want “senior engineer who cares” positioning. Slightly longer name.",
|
||||||
|
color: "#a78bfa",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 28c0-6 4-10 10-10s10 4 10 10" stroke="#a78bfa" stroke-width="2.5" stroke-linecap="round"/><path d="M12 20c0-6 4-10 10-10s10 4 10 10" stroke="#a78bfa" stroke-width="2.5" stroke-linecap="round" opacity="0.45"/><circle cx="22" cy="30" r="2.5" fill="#a78bfa"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "Conduit",
|
||||||
|
sub: "conduit ops",
|
||||||
|
tagline: "The pipe between your tools.",
|
||||||
|
vibe: ["infrastructure", "technical", "integrations"],
|
||||||
|
note: "Strong for webhooks, APIs, custom bridges. Sounds established. Less playful — good for enterprise-ish clients.",
|
||||||
|
color: "#38bdf8",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><rect x="10" y="18" width="24" height="8" rx="4" stroke="#38bdf8" stroke-width="2"/><circle cx="14" cy="22" r="2" fill="#38bdf8"/><circle cx="30" cy="22" r="2" fill="#38bdf8"/><path d="M22 10v8M22 26v8" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "Offload",
|
||||||
|
sub: "offload.work",
|
||||||
|
tagline: "Move tedious work off your plate.",
|
||||||
|
vibe: ["direct", "outcome-first", "plain English"],
|
||||||
|
note: "Zero jargon. Business owners get it in one word. Bold choice — very action-oriented, less “engineer flex.”",
|
||||||
|
color: "#fb923c",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 26h16" stroke="#fb923c" stroke-width="2.5" stroke-linecap="round"/><path d="M22 14v16" stroke="#fb923c" stroke-width="2.5" stroke-linecap="round"/><path d="M18 18l4-4 4 4" stroke="#fb923c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "Quiet Ops",
|
||||||
|
sub: "quietops",
|
||||||
|
tagline: "Runs while you sleep.",
|
||||||
|
vibe: ["calm", "trustworthy", "ops"],
|
||||||
|
note: "Matches your hero copy perfectly. Two words = more memorable story. Feels human, not hype-y. Domain may need a tweak (quietops.co?).",
|
||||||
|
color: "#94a3b8",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 24c0-4 3.5-7 8-7s8 3 8 7" stroke="#94a3b8" stroke-width="2" stroke-linecap="round"/><circle cx="18" cy="18" r="1.5" fill="#94a3b8"/><circle cx="26" cy="18" r="1.5" fill="#94a3b8"/><path d="M20 28h4" stroke="#94a3b8" stroke-width="2" stroke-linecap="round" opacity="0.6"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "Triggerline",
|
||||||
|
sub: "triggerline",
|
||||||
|
tagline: "Event-driven automation, wired right.",
|
||||||
|
vibe: ["webhooks", "real-time", "technical"],
|
||||||
|
note: "Nails your webhook/trigger specialty. Distinctive. Slightly longer — but unique in search results.",
|
||||||
|
color: "#f472b6",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 22h8" stroke="#f472b6" stroke-width="2.5" stroke-linecap="round"/><circle cx="22" cy="22" r="4" stroke="#f472b6" stroke-width="2"/><path d="M26 22h6" stroke="#f472b6" stroke-width="2.5" stroke-linecap="round"/><path d="M22 12v4M22 28v4" stroke="#f472b6" stroke-width="2" stroke-linecap="round" opacity="0.4"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: "Stillrun",
|
||||||
|
sub: "stillrun",
|
||||||
|
tagline: "Always on. Always documented.",
|
||||||
|
vibe: ["uptime", "production", "compact"],
|
||||||
|
note: "One word, modern compound. Implies reliability and 24/7. Works well in terminal mockups: stillrun deploy --target acme",
|
||||||
|
color: "#4ade80",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><rect x="13" y="13" width="6" height="18" rx="2" fill="#4ade80" opacity="0.9"/><rect x="21" y="17" width="6" height="14" rx="2" fill="#4ade80" opacity="0.6"/><rect x="29" y="11" width="6" height="20" rx="2" fill="#4ade80"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: "Patchline",
|
||||||
|
sub: "patchline",
|
||||||
|
tagline: "Scripts, workflows, and the glue in between.",
|
||||||
|
vibe: ["pragmatic", "integrator", "honest"],
|
||||||
|
note: "“Patch” = fix gaps between tools. Feels hands-on and real — not overpromising AI magic. Good for your pragmatic positioning.",
|
||||||
|
color: "#facc15",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 22h8l4-6 4 12 4-8h8" stroke="#facc15" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
name: "Levkin",
|
||||||
|
sub: "levkin · automation",
|
||||||
|
tagline: "Ilia Dobkin — automation engineering.",
|
||||||
|
vibe: ["personal brand", "trust", "no fluff"],
|
||||||
|
note: "Uses your real name. Highest trust for consultancy. Zero naming risk. Downside: harder to sell later if you hire. Logo = monogram.",
|
||||||
|
color: "#e2e8f0",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><text x="22" y="28" text-anchor="middle" fill="#e2e8f0" font-family="system-ui,sans-serif" font-size="18" font-weight="700">LD</text></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: "Clockwork",
|
||||||
|
sub: "clockwork ops",
|
||||||
|
tagline: "Reliable automation that ticks on schedule.",
|
||||||
|
vibe: ["timeless", "dependable", "cron"],
|
||||||
|
note: "Evokes precision without sounding like a toy. Great for scheduled jobs and reports. Slightly old-fashioned — which can read as trustworthy.",
|
||||||
|
color: "#f59e0b",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><circle cx="22" cy="22" r="10" stroke="#f59e0b" stroke-width="2"/><path d="M22 14v8l5 3" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="22" cy="22" r="1.5" fill="#f59e0b"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
name: "Nightshift",
|
||||||
|
sub: "nightshift",
|
||||||
|
tagline: "The work that happens while you're offline.",
|
||||||
|
vibe: ["24/7", "outcome", "memorable"],
|
||||||
|
note: "Direct tie to “runs while you sleep.” Easy story on a sales call. One word, distinctive. Check domain availability.",
|
||||||
|
color: "#818cf8",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M28 18a8 8 0 1 0-10 10" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/><circle cx="30" cy="14" r="1.5" fill="#818cf8"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 13,
|
||||||
|
name: "Splice",
|
||||||
|
sub: "splice.work",
|
||||||
|
tagline: "Join the tools. Ship the workflow.",
|
||||||
|
vibe: ["short", "technical", "integrations"],
|
||||||
|
note: "Five letters, punchy. Implies connecting APIs and data streams. Dev-friendly but not intimidating when paired with plain copy.",
|
||||||
|
color: "#2dd4bf",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 22h8M24 22h8" stroke="#2dd4bf" stroke-width="2.5" stroke-linecap="round"/><rect x="18" y="18" width="8" height="8" rx="2" stroke="#2dd4bf" stroke-width="2"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
name: "Workloom",
|
||||||
|
sub: "workloom",
|
||||||
|
tagline: "Weave your tools into one flow.",
|
||||||
|
vibe: ["craft", "workflows", "warm-tech"],
|
||||||
|
note: "“Loom” suggests weaving threads together — n8n nodes, scripts, webhooks. Softer than pure dev jargon. Unique in search.",
|
||||||
|
color: "#c084fc",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 16h20M12 22h20M12 28h20" stroke="#c084fc" stroke-width="2" stroke-linecap="round" opacity="0.35"/><path d="M14 14c4 4 4 12 0 16M30 14c-4 4-4 12 0 16" stroke="#c084fc" stroke-width="2.5" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 15,
|
||||||
|
name: "Mainline",
|
||||||
|
sub: "mainline automation",
|
||||||
|
tagline: "Production paths, not side projects.",
|
||||||
|
vibe: ["CI/CD", "serious", "pipeline"],
|
||||||
|
note: "Git/main branch energy. Signals you ship real systems, not demos. Strong for engineering buyers; pair with friendly copy for SMBs.",
|
||||||
|
color: "#22d3ee",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 22h20" stroke="#22d3ee" stroke-width="2.5" stroke-linecap="round"/><circle cx="12" cy="22" r="3" fill="#22d3ee"/><circle cx="32" cy="22" r="3" stroke="#22d3ee" stroke-width="2"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 16,
|
||||||
|
name: "Taproot",
|
||||||
|
sub: "taproot systems",
|
||||||
|
tagline: "Automation built in, not bolted on.",
|
||||||
|
vibe: ["foundational", "stable", "organic"],
|
||||||
|
note: "Root = foundation of how work gets done. Less “flashy SaaS,” more “this is how we operate now.” Good for retainers and long-term ops.",
|
||||||
|
color: "#84cc16",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M22 12v8" stroke="#84cc16" stroke-width="2.5" stroke-linecap="round"/><path d="M22 20c-6 0-8 4-8 8M22 20c6 0 8 4 8 8" stroke="#84cc16" stroke-width="2" stroke-linecap="round"/><circle cx="22" cy="12" r="2.5" fill="#84cc16"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 17,
|
||||||
|
name: "Handrail",
|
||||||
|
sub: "handrail",
|
||||||
|
tagline: "Guided automation you can trust.",
|
||||||
|
vibe: ["safe", "consultancy", "human"],
|
||||||
|
note: "Metaphor: you hold the rail while complex ops run safely. Warm for non-technical clients. Less “hacker,” more “partner.”",
|
||||||
|
color: "#94a3b8",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 30V18c0-3 3.5-6 8-6s8 3 8 6v12" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"/><path d="M14 22h16" stroke="#94a3b8" stroke-width="2" stroke-linecap="round" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 18,
|
||||||
|
name: "Clearpath",
|
||||||
|
sub: "clearpath",
|
||||||
|
tagline: "From messy process to obvious workflow.",
|
||||||
|
vibe: ["clarity", "consulting", "SMB-friendly"],
|
||||||
|
note: "Speaks to the discovery call — you help them see what to automate. Approachable, zero jargon. Compound word may be harder to get as .com.",
|
||||||
|
color: "#34d399",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 28 L22 14 L32 28" stroke="#34d399" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/><circle cx="22" cy="24" r="2" fill="#34d399"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 19,
|
||||||
|
name: "Groundwork",
|
||||||
|
sub: "groundwork",
|
||||||
|
tagline: "Lay the foundation. Then let it run.",
|
||||||
|
vibe: ["honest", "build-first", "ops"],
|
||||||
|
note: "Implies you do the hard setup once, then systems run. Fits “production-ready” positioning. Two syllables + work = easy to say.",
|
||||||
|
color: "#d97706",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><rect x="12" y="26" width="20" height="6" rx="1" fill="#d97706" opacity="0.4"/><rect x="14" y="20" width="16" height="6" rx="1" fill="#d97706" opacity="0.65"/><rect x="16" y="14" width="12" height="6" rx="1" fill="#d97706"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 20,
|
||||||
|
name: "Bridgewell",
|
||||||
|
sub: "bridgewell",
|
||||||
|
tagline: "Custom bridges between the tools you already use.",
|
||||||
|
vibe: ["integrations", "custom", "established"],
|
||||||
|
note: "“Bridge” is instantly understood for API work. “Well” adds a slight craft/depth feel. Longer name — but very clear value prop.",
|
||||||
|
color: "#60a5fa",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M10 26h24" stroke="#60a5fa" stroke-width="2.5" stroke-linecap="round"/><path d="M14 26v-6c0-2 3.5-4 8-4s8 2 8 4v6" stroke="#60a5fa" stroke-width="2" stroke-linecap="round"/><circle cx="14" cy="18" r="2" fill="#60a5fa" opacity="0.6"/><circle cx="30" cy="18" r="2" fill="#60a5fa" opacity="0.6"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 21,
|
||||||
|
name: "Hourback",
|
||||||
|
sub: "hourback",
|
||||||
|
tagline: "Buy back the hours lost to manual work.",
|
||||||
|
vibe: ["time saved", "ROI", "plain English"],
|
||||||
|
note: "Instant value prop — clients hear “hours back” and do the math. Logo pairs clock with return arrow. Strong for discovery calls.",
|
||||||
|
color: "#fbbf24",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><circle cx="20" cy="22" r="9" stroke="#fbbf24" stroke-width="2"/><path d="M20 17v5l3 2" stroke="#fbbf24" stroke-width="1.8" stroke-linecap="round"/><path d="M30 18l4 4-4 4" stroke="#fbbf24" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 22,
|
||||||
|
name: "Reclaim",
|
||||||
|
sub: "reclaim ops",
|
||||||
|
tagline: "Reclaim your team's time for work that pays.",
|
||||||
|
vibe: ["time", "empowerment", "outcome"],
|
||||||
|
note: "Active verb — you're taking something back. Less technical, very business-owner friendly. Pairs well with “8 hrs → 90 sec” proof.",
|
||||||
|
color: "#34d399",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M28 16a10 10 0 1 0 2.5 6.5" stroke="#34d399" stroke-width="2.5" stroke-linecap="round"/><path d="M28 10v6h-6" stroke="#34d399" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 23,
|
||||||
|
name: "Timewell",
|
||||||
|
sub: "timewell",
|
||||||
|
tagline: "Time well spent — because the busywork runs itself.",
|
||||||
|
vibe: ["time", "trust", "calm ROI"],
|
||||||
|
note: "Double meaning: time well invested + a well that keeps giving. Softer than “Hourback” but still ROI-forward. Good for retainers.",
|
||||||
|
color: "#5eead4",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><ellipse cx="22" cy="28" rx="8" ry="3" fill="#5eead4" opacity="0.25"/><path d="M18 28V18c0-3 2-5 4-5s4 2 4 5v10" stroke="#5eead4" stroke-width="2" stroke-linecap="round"/><path d="M14 20h16" stroke="#5eead4" stroke-width="2" stroke-linecap="round" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 24,
|
||||||
|
name: "Streamline",
|
||||||
|
sub: "streamline automation",
|
||||||
|
tagline: "Fewer steps. Faster turnaround. Lower cost per task.",
|
||||||
|
vibe: ["streamline", "efficiency", "direct"],
|
||||||
|
note: "Says exactly what you do — no translation needed. Risk: generic word, harder .com. Wins on clarity for SMB buyers who want “make it simpler.”",
|
||||||
|
color: "#38bdf8",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 16h14c4 0 6 2 6 6s-2 6-6 6H12" stroke="#38bdf8" stroke-width="2.5" stroke-linecap="round"/><path d="M32 28H18c-4 0-6-2-6-6s2-6 6-6h14" stroke="#38bdf8" stroke-width="2.5" stroke-linecap="round" opacity="0.45"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 25,
|
||||||
|
name: "Fastlane",
|
||||||
|
sub: "fastlane",
|
||||||
|
tagline: "Skip the manual queue. Ship on autopilot.",
|
||||||
|
vibe: ["speed", "streamline", "motion"],
|
||||||
|
note: "Speed without saying “AI magic.” Familiar metaphor — everyone wants the fast lane. Logo is converging lanes → one path.",
|
||||||
|
color: "#f97316",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 28l6-12h4l6 12" stroke="#f97316" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M24 16h8l-4 12" stroke="#f97316" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 26,
|
||||||
|
name: "Trimwork",
|
||||||
|
sub: "trimwork",
|
||||||
|
tagline: "Trim the busywork. Keep the revenue work.",
|
||||||
|
vibe: ["lean", "pragmatic", "cost cut"],
|
||||||
|
note: "Honest and hands-on — you cut fat from processes. Appeals to owners watching payroll. Less “automation nerd,” more “ops consultant.”",
|
||||||
|
color: "#a3e635",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 30h16" stroke="#a3e635" stroke-width="2" stroke-linecap="round" opacity="0.35"/><path d="M16 24h12" stroke="#a3e635" stroke-width="2" stroke-linecap="round" opacity="0.55"/><path d="M18 18h8" stroke="#a3e635" stroke-width="2.5" stroke-linecap="round"/><path d="M26 14l4 4-10 10H16v-4l10-10z" fill="#a3e635" opacity="0.9"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 27,
|
||||||
|
name: "Yield",
|
||||||
|
sub: "yield automation",
|
||||||
|
tagline: "Automation that yields hours — and margin.",
|
||||||
|
vibe: ["ROI", "money", "compact"],
|
||||||
|
note: "Finance-friendly word — yield on investment, yield per hour. Short, premium. Works in headlines: “Higher yield per employee.”",
|
||||||
|
color: "#22c55e",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M12 30V22c0-6 4-10 10-10s10 4 10 10v8" stroke="#22c55e" stroke-width="2.5" stroke-linecap="round"/><path d="M12 30h20" stroke="#22c55e" stroke-width="2.5" stroke-linecap="round"/><circle cx="22" cy="18" r="2" fill="#22c55e"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 28,
|
||||||
|
name: "Bankable",
|
||||||
|
sub: "bankable hours",
|
||||||
|
tagline: "Turn wasted hours into savings you can count.",
|
||||||
|
vibe: ["money", "measurable", "CFO-friendly"],
|
||||||
|
note: "Speaks to measurable ROI — great when the buyer thinks in dollars, not nodes. Slightly corporate; pair with case-study numbers on the site.",
|
||||||
|
color: "#eab308",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><rect x="12" y="14" width="20" height="16" rx="3" stroke="#eab308" stroke-width="2"/><path d="M16 22h4M24 22h4" stroke="#eab308" stroke-width="2" stroke-linecap="round"/><circle cx="22" cy="22" r="5" stroke="#eab308" stroke-width="1.5" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 29,
|
||||||
|
name: "Compound",
|
||||||
|
sub: "compound ops",
|
||||||
|
tagline: "Small automations. Compounding time savings.",
|
||||||
|
vibe: ["ROI", "growth", "smart"],
|
||||||
|
note: "Investor/business brain candy — savings stack over time. Good story for retainers and ongoing automation roadmaps.",
|
||||||
|
color: "#8b5cf6",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 28c0-8 3.5-14 8-14s8 6 8 14" stroke="#8b5cf6" stroke-width="2" stroke-linecap="round" opacity="0.4"/><path d="M18 24c0-5 2-9 4-9s4 4 4 9" stroke="#8b5cf6" stroke-width="2" stroke-linecap="round" opacity="0.7"/><circle cx="22" cy="16" r="3" fill="#8b5cf6"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 30,
|
||||||
|
name: "Timeshift",
|
||||||
|
sub: "timeshift",
|
||||||
|
tagline: "Shift hours from grunt work to growth work.",
|
||||||
|
vibe: ["time", "transform", "streamline"],
|
||||||
|
note: "Implies moving time to higher-value tasks — not just “faster,” but “better use of payroll.” Distinctive, one word, modern.",
|
||||||
|
color: "#ec4899",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><circle cx="18" cy="22" r="8" stroke="#ec4899" stroke-width="2"/><path d="M18 18v4l3 2" stroke="#ec4899" stroke-width="1.8" stroke-linecap="round"/><path d="M26 22h10M32 18l4 4-4 4" stroke="#ec4899" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 31,
|
||||||
|
name: "Payback",
|
||||||
|
sub: "payback automation",
|
||||||
|
tagline: "Time is money. Get both back.",
|
||||||
|
vibe: ["payback", "hourglass", "ROI"],
|
||||||
|
note: "Says the quiet part out loud — automation pays for itself. Hourglass + return arrow logo. Bold, memorable, slightly aggressive in a good way.",
|
||||||
|
color: "#22c55e",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#22c55e" stroke-width="2" stroke-linejoin="round"/><path d="M18 24h8v6H18z" fill="#22c55e" opacity="0.45"/><path d="M30 14l3 3-6 6" stroke="#22c55e" stroke-width="2" stroke-linecap="round"/><path d="M27 20V14h6" stroke="#22c55e" stroke-width="2" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 32,
|
||||||
|
name: "Timesand",
|
||||||
|
sub: "timesand",
|
||||||
|
tagline: "Stop watching sand run out on manual work.",
|
||||||
|
vibe: ["hourglass", "urgency", "time"],
|
||||||
|
note: "Visual metaphor is instant — sand = time draining on repetitive tasks. Automation plugs the leak. Strong storytelling logo.",
|
||||||
|
color: "#fbbf24",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#fbbf24" stroke-width="2"/><circle cx="20" cy="14" r="1" fill="#fbbf24"/><circle cx="24" cy="17" r="1" fill="#fbbf24" opacity="0.7"/><circle cx="22" cy="21" r="1" fill="#fbbf24" opacity="0.5"/><path d="M18 26h8v5H18z" fill="#fbbf24" opacity="0.35"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 33,
|
||||||
|
name: "Glasshour",
|
||||||
|
sub: "glasshour",
|
||||||
|
tagline: "Every minute automated is a minute earned back.",
|
||||||
|
vibe: ["hourglass", "minimal", "elegant"],
|
||||||
|
note: "Flipped compound — distinctive, ownable. Thin-line hourglass logo feels premium, not gimmicky. Works on dark sites.",
|
||||||
|
color: "#e2e8f0",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M15 11h14M29 33H15M22 21l7-10M22 21l-7-10M22 21l7 12M22 21l-7 12" stroke="#e2e8f0" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 34,
|
||||||
|
name: "Minutebank",
|
||||||
|
sub: "minutebank",
|
||||||
|
tagline: "Deposit minutes. Withdraw margin.",
|
||||||
|
vibe: ["minutes", "money", "hourglass"],
|
||||||
|
note: "Banking metaphor + time — CFOs and owners get it fast. Hourglass with coin slot detail in logo. Playful but serious.",
|
||||||
|
color: "#eab308",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#eab308" stroke-width="2"/><circle cx="22" cy="30" r="5" stroke="#eab308" stroke-width="1.8"/><path d="M22 27v6M19.5 30h5" stroke="#eab308" stroke-width="1.5" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 35,
|
||||||
|
name: "Sandclock",
|
||||||
|
sub: "sandclock",
|
||||||
|
tagline: "The clock is running. Automate before it empties.",
|
||||||
|
vibe: ["hourglass", "urgency", "classic"],
|
||||||
|
note: "Old-word feel, new meaning — like a sandclock on a desk, but for ops. Familiar shape, easy favicon. Slightly literary.",
|
||||||
|
color: "#f97316",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M13 9h18l-9 11 9 11H13l9-11-9-11z" stroke="#f97316" stroke-width="2.2" fill="rgba(249,115,22,0.08)"/><path d="M17 25h10l-5 6-5-6z" fill="#f97316" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 36,
|
||||||
|
name: "Buyback",
|
||||||
|
sub: "buyback time",
|
||||||
|
tagline: "Buy back your team's hours.",
|
||||||
|
vibe: ["payback", "hours", "hourglass"],
|
||||||
|
note: "Parallel to Hourback but hourglass-native. “Buy back” = clear transaction. Good for pricing conversations: you’re purchasing time ROI.",
|
||||||
|
color: "#60a5fa",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#60a5fa" stroke-width="2"/><path d="M28 12c2 4 2 8 0 12" stroke="#60a5fa" stroke-width="2" stroke-linecap="round" opacity="0.6"/><path d="M30 10v4M28 12h4" stroke="#60a5fa" stroke-width="2" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 37,
|
||||||
|
name: "Returnhour",
|
||||||
|
sub: "returnhour",
|
||||||
|
tagline: "Return on every hour you automate.",
|
||||||
|
vibe: ["ROI", "hourglass", "return"],
|
||||||
|
note: "ROI pun built into the name — return + hour. Circular arrow around hourglass in logo. Smart without being cute.",
|
||||||
|
color: "#a78bfa",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#a78bfa" stroke-width="2"/><path d="M30 12a9 9 0 1 0 2 6" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/><path d="M30 8v4h4" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 38,
|
||||||
|
name: "Goldminute",
|
||||||
|
sub: "goldminute",
|
||||||
|
tagline: "Treat every minute like it costs you.",
|
||||||
|
vibe: ["money", "minutes", "premium"],
|
||||||
|
note: "“Time is money” without saying it. Gold sand in hourglass logo = premium consultancy. Pairs with Monochrome Luxe style direction.",
|
||||||
|
color: "#c9a962",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#c9a962" stroke-width="2"/><path d="M17 23h10l-5 7-5-7z" fill="#c9a962" opacity="0.55"/><circle cx="22" cy="14" r="1.2" fill="#c9a962"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 39,
|
||||||
|
name: "Sandflow",
|
||||||
|
sub: "sandflow",
|
||||||
|
tagline: "Let the busywork flow away. Keep the valuable work.",
|
||||||
|
vibe: ["hourglass", "flow", "streamline"],
|
||||||
|
note: "Connects hourglass sand to workflow “flow” — subtle double meaning. Softer than Payback, still time-forward.",
|
||||||
|
color: "#2dd4bf",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#2dd4bf" stroke-width="2"/><path d="M12 32c4-2 8-2 12 0s8 2 12 0" stroke="#2dd4bf" stroke-width="1.8" stroke-linecap="round" opacity="0.5"/></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 40,
|
||||||
|
name: "Paidhour",
|
||||||
|
sub: "paidhour",
|
||||||
|
tagline: "Hours that pay for themselves.",
|
||||||
|
vibe: ["money", "hours", "hourglass"],
|
||||||
|
note: "Direct ROI — every automated hour is a paid hour freed up. Hourglass with checkmark in bottom bulb = job done.",
|
||||||
|
color: "#4ade80",
|
||||||
|
logo: `<svg viewBox="0 0 44 44" fill="none"><rect width="44" height="44" rx="11" fill="#151922"/><path d="M14 10h16l-8 10 8 10H14l8-10-8-10z" stroke="#4ade80" stroke-width="2"/><path d="M19 27l2 2 5-5" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const grid = document.getElementById("options");
|
||||||
|
const pickDisplay = document.getElementById("pick-display");
|
||||||
|
let picked = localStorage.getItem("brand-pick") || "";
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
const batch1 = options.filter((o) => o.id <= 10);
|
||||||
|
const batch2 = options.filter((o) => o.id > 10 && o.id <= 20);
|
||||||
|
const batch3 = options.filter((o) => o.id > 20 && o.id <= 30);
|
||||||
|
const batch4 = options.filter((o) => o.id > 30);
|
||||||
|
|
||||||
|
function cards(list) {
|
||||||
|
return list.map(
|
||||||
|
(o) => `
|
||||||
|
<button type="button" class="option${picked === o.name ? " is-picked" : ""}" data-name="${o.name}" aria-pressed="${picked === o.name}">
|
||||||
|
<span class="option-num">${o.id}</span>
|
||||||
|
<div class="brand-row">
|
||||||
|
<div class="brand-mark">${o.logo}</div>
|
||||||
|
<div>
|
||||||
|
<div class="brand-name">${o.name}<span class="sub">${o.sub}</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="tagline">${o.tagline}</p>
|
||||||
|
<div class="vibe">${o.vibe.map((v) => `<span>${v}</span>`).join("")}</div>
|
||||||
|
<p class="pros-cons"><strong>Take:</strong> ${o.note}</p>
|
||||||
|
</button>`
|
||||||
|
).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.innerHTML =
|
||||||
|
`<p class="batch-label">Round 1 — general</p>` +
|
||||||
|
cards(batch1) +
|
||||||
|
`<p class="batch-label">Round 2</p>` +
|
||||||
|
cards(batch2) +
|
||||||
|
`<p class="batch-label">Round 3 — time, money & streamline</p>` +
|
||||||
|
cards(batch3) +
|
||||||
|
`<p class="batch-label">Round 4 — hourglass logos & payback</p>` +
|
||||||
|
cards(batch4);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPick(name) {
|
||||||
|
picked = name;
|
||||||
|
localStorage.setItem("brand-pick", name);
|
||||||
|
pickDisplay.textContent = name || "none yet";
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.addEventListener("click", (e) => {
|
||||||
|
const card = e.target.closest(".option");
|
||||||
|
if (!card) return;
|
||||||
|
const name = card.dataset.name;
|
||||||
|
setPick(picked === name ? "" : name);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("clear-pick").addEventListener("click", () => setPick(""));
|
||||||
|
document.getElementById("copy-pick").addEventListener("click", () => {
|
||||||
|
if (!picked) return;
|
||||||
|
const o = options.find((x) => x.name === picked);
|
||||||
|
const text = `Brand pick: ${picked}\nTagline: ${o?.tagline || ""}\nVibe: ${o?.vibe?.join(", ") || ""}`;
|
||||||
|
navigator.clipboard?.writeText(text);
|
||||||
|
pickDisplay.textContent = `${picked} (copied!)`;
|
||||||
|
setTimeout(() => {
|
||||||
|
pickDisplay.textContent = picked;
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
|
||||||
|
pickDisplay.textContent = picked || "none yet";
|
||||||
|
render();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2371
docs/style-directions.html
Normal file
566
index.html
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>AutoBank — Automate the boring parts of your business</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Custom automation, scripts, n8n / Zapier / Make workflows, CI/CD pipelines, webhooks, AI integrations, and macOS/iOS Shortcuts. Production-ready automation that doesn't break."
|
||||||
|
/>
|
||||||
|
<meta property="og:title" content="AutoBank" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Production-ready automation for your business — scripts, workflows, pipelines, AI integrations."
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
href="assets/logos/00-full-64.png"
|
||||||
|
type="image/png"
|
||||||
|
/>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="styles.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="#main" class="skip-link">Skip to content</a>
|
||||||
|
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container header-inner">
|
||||||
|
<a href="#top" class="brand" aria-label="AutoBank — Home">
|
||||||
|
<span class="brand-mark-wrap" aria-hidden="true">
|
||||||
|
<img
|
||||||
|
class="brand-mark"
|
||||||
|
id="brand-logo"
|
||||||
|
src="assets/logos/00-full-64.png"
|
||||||
|
width="40"
|
||||||
|
height="40"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="brand-text">
|
||||||
|
<span class="brand-name">AutoBank</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<div class="header-nav">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nav-toggle"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="primary-nav"
|
||||||
|
>
|
||||||
|
<span class="nav-toggle-icon" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden">Menu</span>
|
||||||
|
</button>
|
||||||
|
<nav id="primary-nav" class="primary-nav" aria-label="Primary">
|
||||||
|
<a href="#services">Services</a>
|
||||||
|
<a href="#process">Process</a>
|
||||||
|
<a href="#why">Why me</a>
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" class="nav-cta" target="_blank" rel="noopener"
|
||||||
|
>Book a call<span class="visually-hidden"> (opens in new tab)</span></a
|
||||||
|
>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main id="main">
|
||||||
|
<!-- HERO -->
|
||||||
|
<section id="top" class="hero">
|
||||||
|
<div class="hero-bg" aria-hidden="true">
|
||||||
|
<div class="grid-bg"></div>
|
||||||
|
<div class="glow glow-1"></div>
|
||||||
|
<div class="glow glow-2"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container hero-inner">
|
||||||
|
<div class="hero-eyebrow">
|
||||||
|
<span class="pulse"></span>
|
||||||
|
<span>Currently taking on new automation projects</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="hero-title">
|
||||||
|
Automate the boring parts<br />
|
||||||
|
of your business.
|
||||||
|
<span class="cursor" aria-hidden="true"></span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="hero-lede">
|
||||||
|
I build production-ready automation that runs while you sleep — custom scripts, no-code workflows,
|
||||||
|
CI/CD pipelines, webhooks, AI integrations. Less manual work. Faster turnaround. Fewer mistakes.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="hero-cta-row">
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" class="btn btn-primary" target="_blank" rel="noopener">
|
||||||
|
Book a free 15-min call<span class="visually-hidden"> (opens in new tab)</span>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||||||
|
<path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="#services" class="btn btn-ghost">See what I build</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Terminal-ish window -->
|
||||||
|
<div class="terminal" aria-hidden="true">
|
||||||
|
<div class="terminal-bar">
|
||||||
|
<span class="dot red"></span>
|
||||||
|
<span class="dot yellow"></span>
|
||||||
|
<span class="dot green"></span>
|
||||||
|
<span class="terminal-title">~/your-business — autobank.sh</span>
|
||||||
|
</div>
|
||||||
|
<pre class="terminal-body"><span class="prompt">></span> <span class="cmd">RUN AUTO_PIPELINE target=your-business</span>
|
||||||
|
<span class="muted">[sys] Connecting Gmail, Slack, Notion, HubSpot, Stripe…</span>
|
||||||
|
<span class="muted">[sys] Workflow: <span class="hl">lead-intake → enrich → notify → CRM</span></span>
|
||||||
|
<span class="muted">[sys] Cron + webhooks armed</span>
|
||||||
|
<span class="ok">[PASS] 14 manual steps eliminated</span>
|
||||||
|
<span class="ok">[PASS] Avg turnaround: 8 hrs → 90 sec</span>
|
||||||
|
<span class="ok">[PASS] Production ready · monitored · documented</span>
|
||||||
|
<span class="prompt blink">></span></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- LOGOS / PROOF STRIP -->
|
||||||
|
<section class="strip" aria-label="Tools I work with">
|
||||||
|
<div class="container">
|
||||||
|
<p class="strip-label">Tools I work with</p>
|
||||||
|
<ul class="strip-list">
|
||||||
|
<li>n8n</li>
|
||||||
|
<li>Zapier</li>
|
||||||
|
<li>Make</li>
|
||||||
|
<li>GitHub Actions</li>
|
||||||
|
<li>OpenAI</li>
|
||||||
|
<li>Claude</li>
|
||||||
|
<li>Webhooks</li>
|
||||||
|
<li>Shortcuts</li>
|
||||||
|
<li>Python · Node · Bash</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- SERVICES -->
|
||||||
|
<section id="services" class="section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<p class="kicker">What I build</p>
|
||||||
|
<h2>From a small script that saves an hour a day,<br />to full pipelines that run your operations.</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-grid">
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<rect x="3" y="3" width="18" height="18" rx="3" />
|
||||||
|
<path d="M8 9h8M8 13h8M8 17h5" stroke-linecap="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>Custom scripts & CLI tools</h3>
|
||||||
|
<p>Python, Node, and Bash automations that take a repetitive task and reduce it to one command — or zero.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<circle cx="6" cy="6" r="2.5" />
|
||||||
|
<circle cx="18" cy="6" r="2.5" />
|
||||||
|
<circle cx="6" cy="18" r="2.5" />
|
||||||
|
<circle cx="18" cy="18" r="2.5" />
|
||||||
|
<path d="M8.5 6h7M6 8.5v7M18 8.5v7M8.5 18h7" stroke-linecap="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>n8n, Zapier & Make workflows</h3>
|
||||||
|
<p>No-code workflows that connect the tools you already use — Gmail, Slack, Notion, HubSpot, Stripe, Sheets, and 500+ more.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<path d="M4 6h16M4 12h16M4 18h16" stroke-linecap="round" />
|
||||||
|
<circle cx="8" cy="6" r="2" fill="currentColor" stroke="none" />
|
||||||
|
<circle cx="16" cy="12" r="2" fill="currentColor" stroke="none" />
|
||||||
|
<circle cx="10" cy="18" r="2" fill="currentColor" stroke="none" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>CI/CD pipelines</h3>
|
||||||
|
<p>GitHub Actions, Jenkins, Azure DevOps. Build, test, and deployment pipelines that turn manual hours into automated minutes.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<path d="M12 3v6M12 15v6M3 12h6M15 12h6" stroke-linecap="round" />
|
||||||
|
<circle cx="12" cy="12" r="3" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>Webhooks & triggers</h3>
|
||||||
|
<p>Event-driven systems that react in real time — form submissions, payments, support tickets, file uploads, anything with an API.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<path d="M12 2l2.4 5.6L20 9l-4 4 1 6-5-3-5 3 1-6-4-4 5.6-1.4z" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>AI & LLM integrations</h3>
|
||||||
|
<p>Drop GPT, Claude, or local models into real workflows — summarize email, triage tickets, extract data, draft replies, generate reports.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<path d="M12 7v5l3 2" stroke-linecap="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>Scheduled jobs & reports</h3>
|
||||||
|
<p>Daily digests, weekly KPIs, end-of-month reports — running on schedule, landing where your team already lives.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<rect x="5" y="2" width="14" height="20" rx="3" />
|
||||||
|
<path d="M10 18h4" stroke-linecap="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>macOS & iOS Shortcuts</h3>
|
||||||
|
<p>Personal productivity automations — one tap to capture, route, summarize, or trigger workflows from your phone or Mac.</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon">
|
||||||
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
|
||||||
|
<path d="M4 4l16 8-16 8 4-8z" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3>Custom integrations</h3>
|
||||||
|
<p>When off-the-shelf connectors don't cut it — custom APIs, OAuth flows, and bridges between systems that weren't meant to talk.</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="services-footnote">
|
||||||
|
Don't see your use case? Most automation problems look unique until you describe them out loud.
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" target="_blank" rel="noopener"
|
||||||
|
>Tell me what you're stuck on.<span class="visually-hidden"> (opens in new tab)</span></a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- OUTCOMES BAND -->
|
||||||
|
<section class="outcomes" aria-label="Key outcomes">
|
||||||
|
<div class="container outcomes-inner">
|
||||||
|
<div class="outcome">
|
||||||
|
<div class="outcome-num">10×</div>
|
||||||
|
<div class="outcome-label">faster workflows than manual</div>
|
||||||
|
</div>
|
||||||
|
<div class="outcome">
|
||||||
|
<div class="outcome-num">24/7</div>
|
||||||
|
<div class="outcome-label">runs without you watching it</div>
|
||||||
|
</div>
|
||||||
|
<div class="outcome">
|
||||||
|
<div class="outcome-num">0</div>
|
||||||
|
<div class="outcome-label">copy-paste errors at 2 a.m.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- PROCESS -->
|
||||||
|
<section id="process" class="section section-alt">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<p class="kicker">How it works</p>
|
||||||
|
<h2>Four steps. Production-ready at the end of them.</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ol class="process-list">
|
||||||
|
<li class="process-step">
|
||||||
|
<div class="step-num">01</div>
|
||||||
|
<div>
|
||||||
|
<h3>Discover</h3>
|
||||||
|
<p>Free 15-min call. You describe the painful part of your workflow. I tell you whether automation makes sense — honestly.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="process-step">
|
||||||
|
<div class="step-num">02</div>
|
||||||
|
<div>
|
||||||
|
<h3>Design</h3>
|
||||||
|
<p>A short proposal: what gets automated, which tools, how long it'll take, what it costs. No surprises.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="process-step">
|
||||||
|
<div class="step-num">03</div>
|
||||||
|
<div>
|
||||||
|
<h3>Ship</h3>
|
||||||
|
<p>I build it, test it, document it, and walk you through it. Production-ready means it survives bad data, retries, and a Monday morning.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="process-step">
|
||||||
|
<div class="step-num">04</div>
|
||||||
|
<div>
|
||||||
|
<h3>Maintain</h3>
|
||||||
|
<p>Optional ongoing support — monitoring, tweaks, and new automations as your business grows.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- USE CASES -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<p class="kicker">Examples</p>
|
||||||
|
<h2>Things teams hire me to automate.</h2>
|
||||||
|
</div>
|
||||||
|
<div class="usecase-grid">
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Sales</span>
|
||||||
|
<p>New lead arrives → enriched in Clearbit/Apollo → scored → routed to the right rep on Slack → logged in CRM. All in seconds.</p>
|
||||||
|
</div>
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Support</span>
|
||||||
|
<p>Incoming tickets summarized by an LLM, tagged by topic, severity-scored, and drafted with a suggested reply for an agent to send.</p>
|
||||||
|
</div>
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Ops</span>
|
||||||
|
<p>End-of-day reports pulled from Stripe, Shopify, and Sheets — assembled into a single Slack digest at 6 p.m. sharp.</p>
|
||||||
|
</div>
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Marketing</span>
|
||||||
|
<p>Blog post published → auto-generate social copy → schedule across LinkedIn, X, and Bluesky → log performance back into Notion.</p>
|
||||||
|
</div>
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Engineering</span>
|
||||||
|
<p>Pull request opened → tests run → preview deployed → screenshots posted as a comment → Slack notified. Faster reviews, fewer regressions.</p>
|
||||||
|
</div>
|
||||||
|
<div class="usecase">
|
||||||
|
<span class="usecase-tag">Personal</span>
|
||||||
|
<p>One Shortcut on your phone: captures voice → transcribes → routes to the right project in your Notion or Things inbox.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- WHY ME -->
|
||||||
|
<section id="why" class="section section-alt">
|
||||||
|
<div class="container">
|
||||||
|
<div class="why-grid">
|
||||||
|
<div>
|
||||||
|
<p class="kicker">Why me</p>
|
||||||
|
<h2>15+ years building automation that has to work.</h2>
|
||||||
|
<p class="why-lede">
|
||||||
|
I come from a software engineering background — JavaScript, .NET, CI/CD pipelines, and large enterprise
|
||||||
|
products where automation isn't a nice-to-have, it's how releases ship at all. That same engineering
|
||||||
|
discipline is what I bring to your business automation.
|
||||||
|
</p>
|
||||||
|
<ul class="why-list">
|
||||||
|
<li><strong>Production-ready by default.</strong> Error handling, retries, alerts, logs — not a happy-path demo.</li>
|
||||||
|
<li><strong>Documented.</strong> You shouldn't need me to understand what's running.</li>
|
||||||
|
<li><strong>Tested.</strong> Before it touches your live data.</li>
|
||||||
|
<li><strong>Pragmatic.</strong> A 20-line script often beats a 200-node workflow. I'll tell you which one you need.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<aside class="why-card">
|
||||||
|
<p class="why-card-eyebrow">Signature outcome</p>
|
||||||
|
<p class="why-card-stat">8 hrs → < 2 min</p>
|
||||||
|
<p class="why-card-desc">
|
||||||
|
Release pipeline I built for an enterprise client — turning a multi-hour manual ritual into a
|
||||||
|
fully scripted, hands-off process. The same approach scales down to a small business saving an
|
||||||
|
hour a day on quote follow-ups.
|
||||||
|
</p>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- FAQ -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-head">
|
||||||
|
<p class="kicker">FAQ</p>
|
||||||
|
<h2>Common questions.</h2>
|
||||||
|
</div>
|
||||||
|
<div class="faq">
|
||||||
|
<details>
|
||||||
|
<summary>How much does a typical automation cost?</summary>
|
||||||
|
<p>Most projects land between a quick fixed-fee script and a multi-week build. I quote per project after the discovery call — no hourly billing surprises.</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Do I need to use a specific tool?</summary>
|
||||||
|
<p>No. I pick the right tool for the job — sometimes it's n8n, sometimes Zapier, sometimes a custom script. I'll explain the tradeoffs in plain language.</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>What if I'm not sure automation is worth it?</summary>
|
||||||
|
<p>That's exactly what the free 15-min call is for. If automating a process won't pay back the cost of building it, I'll tell you.</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Do you work with companies outside Canada?</summary>
|
||||||
|
<p>Yes — fully remote, comfortable across North American and European time zones.</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Can you maintain what you build?</summary>
|
||||||
|
<p>Optional. I can hand it off with documentation, or stay on for monitoring and ongoing improvements.</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- BOOK / CTA -->
|
||||||
|
<section id="book" class="cta-section">
|
||||||
|
<div class="cta-bg" aria-hidden="true">
|
||||||
|
<div class="grid-bg"></div>
|
||||||
|
<div class="glow glow-3"></div>
|
||||||
|
</div>
|
||||||
|
<div class="container cta-inner">
|
||||||
|
<p class="kicker kicker-light">Let's talk</p>
|
||||||
|
<h2>Book a free 15-minute consultation.</h2>
|
||||||
|
<p class="cta-lede">
|
||||||
|
Tell me about the part of your business that drains the most time. I'll tell you whether it's
|
||||||
|
worth automating — and if it is, exactly how I'd do it.
|
||||||
|
</p>
|
||||||
|
<div class="cta-row">
|
||||||
|
<a class="btn btn-primary btn-large" href="https://cal.levkin.ca/ilia/consult" target="_blank" rel="noopener">
|
||||||
|
Pick a time — 15 min free<span class="visually-hidden"> (opens in new tab)</span>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-ghost btn-large" href="mailto:ilia@levkine.ca?subject=Automation%20consultation%20(15%20min)&body=Hi%20Ilia%2C%0A%0AI%27d%20like%20to%20book%20a%2015-min%20consultation.%20Here%27s%20what%20I%27m%20looking%20to%20automate%3A%0A%0A">
|
||||||
|
Or email instead
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<p class="cta-foot">No commitment. No sales pitch. Just a conversation.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="container footer-inner">
|
||||||
|
<p>© <span id="year"></span> AutoBank · Ilia Dobkin</p>
|
||||||
|
<p class="footer-meta">
|
||||||
|
Greater Toronto Area ·
|
||||||
|
<a href="mailto:ilia@levkine.ca">ilia@levkine.ca</a>
|
||||||
|
·
|
||||||
|
<a href="https://www.linkedin.com/in/ilia-dobkin-8263343/" target="_blank" rel="noopener"
|
||||||
|
>LinkedIn<span class="visually-hidden"> (opens in new tab)</span></a
|
||||||
|
>
|
||||||
|
·
|
||||||
|
<a href="https://git.levkin.ca" target="_blank" rel="noopener"
|
||||||
|
>git.levkin.ca<span class="visually-hidden"> (opens in new tab)</span></a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("year").textContent = new Date().getFullYear();
|
||||||
|
|
||||||
|
const navToggle = document.querySelector(".nav-toggle");
|
||||||
|
const primaryNav = document.getElementById("primary-nav");
|
||||||
|
|
||||||
|
function setNavOpen(open) {
|
||||||
|
if (!navToggle || !primaryNav) return;
|
||||||
|
navToggle.setAttribute("aria-expanded", String(open));
|
||||||
|
primaryNav.classList.toggle("is-open", open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (navToggle && primaryNav) {
|
||||||
|
navToggle.addEventListener("click", () => {
|
||||||
|
setNavOpen(navToggle.getAttribute("aria-expanded") !== "true");
|
||||||
|
});
|
||||||
|
primaryNav.querySelectorAll("a").forEach((link) => {
|
||||||
|
link.addEventListener("click", () => setNavOpen(false));
|
||||||
|
});
|
||||||
|
document.addEventListener("keydown", (e) => {
|
||||||
|
if (e.key === "Escape") setNavOpen(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOGO_FRAMES = [
|
||||||
|
"assets/logos/00-full-64.png",
|
||||||
|
"assets/logos/01-25pct-64.png",
|
||||||
|
"assets/logos/02-15pct-64.png",
|
||||||
|
"assets/logos/03-3grains-64.png",
|
||||||
|
"assets/logos/04-1grain-64.png",
|
||||||
|
];
|
||||||
|
|
||||||
|
LOGO_FRAMES.forEach((src) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = src;
|
||||||
|
});
|
||||||
|
|
||||||
|
const brandLogo = document.getElementById("brand-logo");
|
||||||
|
const motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||||
|
let prefersReducedMotion = motionQuery.matches;
|
||||||
|
motionQuery.addEventListener("change", (e) => {
|
||||||
|
prefersReducedMotion = e.matches;
|
||||||
|
});
|
||||||
|
|
||||||
|
function logoIndexFromScroll() {
|
||||||
|
const doc = document.documentElement;
|
||||||
|
const max = doc.scrollHeight - window.innerHeight;
|
||||||
|
if (max <= 0) return 0;
|
||||||
|
const progress = Math.min(1, Math.max(0, window.scrollY / max));
|
||||||
|
return Math.min(LOGO_FRAMES.length - 1, Math.floor(progress * LOGO_FRAMES.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
let logoTicking = false;
|
||||||
|
function updateBrandLogo() {
|
||||||
|
if (!brandLogo || prefersReducedMotion) return;
|
||||||
|
const idx = logoIndexFromScroll();
|
||||||
|
const next = LOGO_FRAMES[idx];
|
||||||
|
if (brandLogo.getAttribute("src") === next) return;
|
||||||
|
brandLogo.src = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onScrollFrame() {
|
||||||
|
updateBrandLogo();
|
||||||
|
logoTicking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = document.querySelector(".site-header");
|
||||||
|
const onScroll = () => {
|
||||||
|
header.classList.toggle("is-scrolled", window.scrollY > 8);
|
||||||
|
if (!logoTicking) {
|
||||||
|
logoTicking = true;
|
||||||
|
requestAnimationFrame(onScrollFrame);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onScroll();
|
||||||
|
updateBrandLogo();
|
||||||
|
window.addEventListener("scroll", onScroll, { passive: true });
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
updateBrandLogo();
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
if ("IntersectionObserver" in window && !prefersReducedMotion) {
|
||||||
|
document.documentElement.classList.add("js-reveal");
|
||||||
|
const targets = document.querySelectorAll(
|
||||||
|
".section, .hero-inner, .service-card, .process-step, .usecase, .why-grid, .terminal"
|
||||||
|
);
|
||||||
|
const io = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((e) => {
|
||||||
|
if (e.isIntersecting) {
|
||||||
|
e.target.classList.add("is-in");
|
||||||
|
io.unobserve(e.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ threshold: 0.08, rootMargin: "0px 0px -40px 0px" }
|
||||||
|
);
|
||||||
|
targets.forEach((el) => {
|
||||||
|
el.classList.add("reveal");
|
||||||
|
io.observe(el);
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
targets.forEach((el) => el.classList.add("is-in"));
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
641
package-lock.json
generated
Normal file
@ -0,0 +1,641 @@
|
|||||||
|
{
|
||||||
|
"name": "autobank-site",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "autobank-site",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"devDependencies": {
|
||||||
|
"sharp": "^0.34.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emnapi/runtime": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/colour": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-ppc64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-riscv64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-s390x": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-wasm32": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
|
||||||
|
"cpu": [
|
||||||
|
"wasm32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/runtime": "^1.7.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-ia32": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "7.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
|
||||||
|
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sharp": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@img/colour": "^1.0.0",
|
||||||
|
"detect-libc": "^2.1.2",
|
||||||
|
"semver": "^7.7.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-darwin-arm64": "0.34.5",
|
||||||
|
"@img/sharp-darwin-x64": "0.34.5",
|
||||||
|
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-arm": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-x64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
||||||
|
"@img/sharp-linux-arm": "0.34.5",
|
||||||
|
"@img/sharp-linux-arm64": "0.34.5",
|
||||||
|
"@img/sharp-linux-ppc64": "0.34.5",
|
||||||
|
"@img/sharp-linux-riscv64": "0.34.5",
|
||||||
|
"@img/sharp-linux-s390x": "0.34.5",
|
||||||
|
"@img/sharp-linux-x64": "0.34.5",
|
||||||
|
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
||||||
|
"@img/sharp-linuxmusl-x64": "0.34.5",
|
||||||
|
"@img/sharp-wasm32": "0.34.5",
|
||||||
|
"@img/sharp-win32-arm64": "0.34.5",
|
||||||
|
"@img/sharp-win32-ia32": "0.34.5",
|
||||||
|
"@img/sharp-win32-x64": "0.34.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "0BSD",
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "autobank-site",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "AutoBank — static landing page for automation consulting",
|
||||||
|
"scripts": {
|
||||||
|
"logos:normalize": "node scripts/normalize-logos.mjs",
|
||||||
|
"logos:match-full": "node scripts/match-full-brightness.mjs assets/logos/source/hourglass-mint-full-v2.png"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sharp": "^0.34.2"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@gitea.levkin.ca:ilia/auto.git"
|
||||||
|
},
|
||||||
|
"license": "UNLICENSED"
|
||||||
|
}
|
||||||
40
scripts/match-full-brightness.mjs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import sharp from "sharp";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const REF = "assets/logos/source/hourglass-mint-25pct.png";
|
||||||
|
const FULL = process.argv[2];
|
||||||
|
const OUT = "assets/logos/source/hourglass-mint-full.png";
|
||||||
|
|
||||||
|
if (!FULL || !existsSync(FULL)) {
|
||||||
|
console.error("Usage: node scripts/match-full-brightness.mjs <draft-full.png>");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mean luminance of non-black pixels (0–255). */
|
||||||
|
async function meanLuma(path) {
|
||||||
|
const { data } = await sharp(path).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
||||||
|
let sum = 0;
|
||||||
|
let n = 0;
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
const r = data[i];
|
||||||
|
const g = data[i + 1];
|
||||||
|
const b = data[i + 2];
|
||||||
|
const l = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||||
|
if (l > 12) {
|
||||||
|
sum += l;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n ? sum / n : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const refLuma = await meanLuma(REF);
|
||||||
|
let fullLuma = await meanLuma(FULL);
|
||||||
|
const brightness = Math.min(1, Math.max(0.72, (refLuma / fullLuma) * 0.96));
|
||||||
|
|
||||||
|
await sharp(FULL).modulate({ brightness, saturation: 0.92 }).png().toFile(OUT);
|
||||||
|
|
||||||
|
fullLuma = await meanLuma(OUT);
|
||||||
|
console.log(`ref ${refLuma.toFixed(1)} → out ${fullLuma.toFixed(1)} (brightness ${brightness.toFixed(3)})`);
|
||||||
|
console.log(`wrote ${OUT} — run npm run logos:normalize`);
|
||||||
50
scripts/normalize-logos.mjs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import sharp from "sharp";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const SRC = "assets/logos/source";
|
||||||
|
const OUT = "assets/logos";
|
||||||
|
const SIZE = 128;
|
||||||
|
const ICON_W = 56;
|
||||||
|
const ICON_H = 96;
|
||||||
|
|
||||||
|
const sources = [
|
||||||
|
["hourglass-mint-full.png", "00-full"],
|
||||||
|
["hourglass-mint-25pct.png", "01-25pct"],
|
||||||
|
["hourglass-mint-15pct.png", "02-15pct"],
|
||||||
|
["hourglass-mint-3grains.png", "03-3grains"],
|
||||||
|
["hourglass-mint-1grain.png", "04-1grain"],
|
||||||
|
];
|
||||||
|
|
||||||
|
async function normalize(input, name) {
|
||||||
|
const pipeline = sharp(input).ensureAlpha().trim({ threshold: 12 });
|
||||||
|
const trimmed = await pipeline.toBuffer();
|
||||||
|
const meta = await sharp(trimmed).metadata();
|
||||||
|
|
||||||
|
const icon = await sharp(trimmed)
|
||||||
|
.resize(ICON_W, ICON_H, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
||||||
|
.extend({
|
||||||
|
top: Math.floor((SIZE - ICON_H) / 2),
|
||||||
|
bottom: Math.ceil((SIZE - ICON_H) / 2),
|
||||||
|
left: Math.floor((SIZE - ICON_W) / 2),
|
||||||
|
right: Math.ceil((SIZE - ICON_W) / 2),
|
||||||
|
background: { r: 0, g: 0, b: 0, alpha: 1 },
|
||||||
|
})
|
||||||
|
.flatten({ background: { r: 0, g: 0, b: 0 } })
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
await sharp(icon).resize(128, 128).toFile(join(OUT, `${name}-128.png`));
|
||||||
|
await sharp(icon).resize(64, 64).toFile(join(OUT, `${name}-64.png`));
|
||||||
|
|
||||||
|
console.log(`${name}: ${meta.width}x${meta.height} → ${ICON_W}x${ICON_H} → 64/128px`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [file, name] of sources) {
|
||||||
|
const path = join(SRC, file);
|
||||||
|
if (!existsSync(path)) {
|
||||||
|
console.warn("skip missing", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await normalize(path, name);
|
||||||
|
}
|
||||||