90
docs/design_handoff_waggle_app/DESIGN_POV.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# DESIGN_POV.md — strategic notes from the design pass
|
||||
|
||||
> These are **convictions, not tickets** — observations from living inside Waggle
|
||||
> while designing it. They go beyond the brief. One (#1, Memory Trust) is already
|
||||
> built into this package as a screen (`screens/memory-trust.html`, doc section
|
||||
> "Trust"). The other four are open questions worth a decision before — or shortly
|
||||
> after — the refactor ships. Treat this as a starting point for the team, not a
|
||||
> spec.
|
||||
|
||||
---
|
||||
|
||||
## 1. Memory you can trust · **BUILT — see `memory-trust.html`**
|
||||
|
||||
**The risk.** A persistent-memory product's #1 churn driver isn't *forgetting* — it's
|
||||
**remembering the wrong thing**, acting on something stale, or knowing something the
|
||||
user wishes it didn't. The concept (rightly) sells memory as an asset that compounds.
|
||||
But the first time Waggle confidently does the wrong thing because of a bad memory,
|
||||
trust breaks — and trust is the entire reason someone leaves their working life in the
|
||||
hive.
|
||||
|
||||
**The response (designed).** A *Memory Trust* layer:
|
||||
- **Confidence + freshness** on every memory (the agent and the user can both discount
|
||||
what's shaky or old instead of acting on it blindly).
|
||||
- **Forget** (real removal from recall + from anything said next) and **Correct**
|
||||
(inline; dependents re-checked) on any memory.
|
||||
- **Stale review** prompts ("this is 6 weeks old — still true?").
|
||||
- **"Why did you do that?" trace** — any agent action unfolds into goal → recalled
|
||||
memories (with confidence) → checks → action, and the fix (correct/forget the
|
||||
offending memory) is one click from the explanation.
|
||||
|
||||
**Why it's also a moat.** Editable, accountable memory is *harder* to build than
|
||||
accumulating memory, and it's exactly what enterprise/KVARK buyers will demand
|
||||
(auditability, right-to-correct, EU AI Act alignment). It turns the scariest property
|
||||
of the product into its most trustworthy one.
|
||||
|
||||
---
|
||||
|
||||
## 2. The cold-start inversion
|
||||
|
||||
**The problem.** Waggle is **worst on day one** (knows nothing) and best on day 365 —
|
||||
the value curve runs backwards exactly when you're trying to convert someone. Import
|
||||
helps, but the first week is make-or-break and isn't yet designed as a deliberate arc.
|
||||
|
||||
**Suggested response.** A "worth it before it's full" thread: honest, inviting empty
|
||||
states; and an explicit, **celebrated first aha moment** — the first time Waggle
|
||||
surfaces *"I remembered X so you didn't have to,"* made a felt moment rather than a
|
||||
silent convenience. Measure time-to-first-recall as a north-star activation metric.
|
||||
|
||||
---
|
||||
|
||||
## 3. Voice & lexicon (commit to the metaphor — carefully)
|
||||
|
||||
The bee system (Waggle / hive / waggle-dance / "while you slept") is charming but
|
||||
half-committed; it wobbles between cute and technical. There's a coherent, restrained
|
||||
metaphor here (the dance = diffusion is already used well). **Write a short voice &
|
||||
lexicon guide:** which bee-words earn their place (hive, waggle-dance), which stay
|
||||
plain (memory, agents, connectors), and a hard rule that the enterprise/KVARK surface
|
||||
stays sober. Consistency makes it feel intentional instead of themed.
|
||||
|
||||
---
|
||||
|
||||
## 4. Who pays for inference?
|
||||
|
||||
The pricing story ("memory free forever, pay for scale") is clean — but the project's
|
||||
**own benchmark admits high token use**, and tokens are the real cost. The unmade
|
||||
decision: **BYO-key** (user pays the provider directly — fits local-first, keeps
|
||||
margins clean, but adds onboarding friction) **vs. Waggle-metered** (smoother UX, but
|
||||
you carry inference cost + need usage caps). This quietly reshapes Billing, Onboarding
|
||||
(the model gate), and Usage. Decide it explicitly before the billing flow ships; the
|
||||
current design supports either but commits to neither.
|
||||
|
||||
---
|
||||
|
||||
## 5. The morning briefing as a *ritual*
|
||||
|
||||
The habit loop is solid; the most ownable version of the trigger is a **60-second
|
||||
briefing you could listen to** — "Waggle reads you your morning." Audio is sticky,
|
||||
daily, hands-free, and nobody in the agent category has it. A natural extension of the
|
||||
Home cockpit + the "while you slept" summary, and a strong hook for the mobile +
|
||||
messaging surfaces on the roadmap.
|
||||
|
||||
---
|
||||
|
||||
### How to use this
|
||||
- #1 is done — review the screen and wire it to the real memory store
|
||||
(confidence/freshness/forget/correct/trace are all backed by data the substrate
|
||||
already has or can derive).
|
||||
- #2–#5 are decisions for product + design leadership. None blocks the refactor, but
|
||||
#4 (inference cost) should be settled before Billing goes live, and #1's trust
|
||||
primitives should land early because everything else trades on them.
|
||||
333
docs/design_handoff_waggle_app/README.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# Handoff: Waggle — App + Landing Refactor (the "warm Hive" concept)
|
||||
|
||||
> A complete design concept for refactoring **Waggle OS** — the persistent-memory,
|
||||
> local-first, model-agnostic AI workspace (monorepo: `marolinik/waggle-os`,
|
||||
> memory substrate: `marolinik/hive-mind`). This package contains **22 interactive
|
||||
> HTML design references** plus the design-system stylesheet, and the brief to
|
||||
> recreate them in the real codebase.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
Waggle is a workspace-native AI agent platform: persistent memory that compounds,
|
||||
model-agnostic orchestration (Claude / GPT / Gemini / **local** models), a skills +
|
||||
connectors marketplace, a multi-agent "waggle-dance" swarm, and an "AI-OS" launcher
|
||||
that runs external coding agents (Claude Code, Cursor, Codex…) **inside a workspace's
|
||||
shared memory**. It ships as a **Tauri desktop app for Windows + macOS**.
|
||||
|
||||
This concept is a top-to-bottom redesign addressing five problems found in the live
|
||||
product:
|
||||
|
||||
1. **Overloaded navigation** — ~18 always-visible destinations across 5 zones.
|
||||
2. **Engineer-first language** — "Spawn", "Waggle-Dance", "MCPs", "GEPA".
|
||||
3. **Uniform 10–13px density** — reads as a control panel, never premium.
|
||||
4. **Five semantic colors firing at once** over glass + wallpaper + honeycomb.
|
||||
5. **Hidden differentiators** — memory, overnight work, coordination buried in tallies.
|
||||
|
||||
The response is a **warmer "Hive" identity**, a **5-item spine + ⌘K command bar**
|
||||
(progressive disclosure), **plain-language labels with the technical term as a
|
||||
subtitle**, and **legible "hero moments"** for the differentiators.
|
||||
|
||||
**Target users:** knowledge workers / operators (non-technical first), without
|
||||
removing any depth power users need.
|
||||
|
||||
---
|
||||
|
||||
## 2. About the design files (READ THIS FIRST)
|
||||
|
||||
The files in `design-files/` are **design references created in HTML** — interactive
|
||||
prototypes that show intended **look, layout, copy, and behavior**. They are **not
|
||||
production code to copy verbatim.**
|
||||
|
||||
**Your task:** recreate these designs inside the **existing Waggle codebase**
|
||||
(`apps/web` is React + TypeScript + Vite + Tailwind + shadcn/ui + React Router;
|
||||
`apps/www` is the Next.js marketing site), using its established components,
|
||||
routing, state, and data layer. Where this concept introduces a new pattern (e.g.
|
||||
the ⌘K palette, the warm token set), implement it in the codebase's idiom — don't
|
||||
paste HTML/inline styles.
|
||||
|
||||
Two files are the entry points:
|
||||
- **`Waggle Reimagined.html`** — the concept narrative + an index that embeds every
|
||||
app screen in an iframe. Open it first; its top nav links to every section.
|
||||
- **`Waggle Landing.html`** — the redesigned public marketing site (`apps/www`).
|
||||
|
||||
Everything shares **one stylesheet: `design-files/styles/waggle.css`** — the source
|
||||
of truth for tokens (see §7).
|
||||
|
||||
---
|
||||
|
||||
## 3. Fidelity
|
||||
|
||||
**High-fidelity.** Final colors, typography, spacing, radii, shadows, motion, and
|
||||
copy are all intentional and specified in §7 and the per-screen appendix (§10).
|
||||
Recreate the UI pixel-faithfully using the codebase's existing libraries — map the
|
||||
tokens in `waggle.css` onto the Tailwind theme / CSS variables, then build screens
|
||||
with shadcn/ui primitives styled to match.
|
||||
|
||||
One caveat: the prototypes use vanilla JS for view-switching and the dark/light
|
||||
toggle. That plumbing is **demonstration scaffolding** — replace it with real React
|
||||
state, React Router routes, and the app's theme provider. The visuals, layout, and
|
||||
interaction *design* are what to preserve.
|
||||
|
||||
---
|
||||
|
||||
## 4. Information architecture (the spine)
|
||||
|
||||
Collapse ~18 destinations into **5 everyday places**, with everything else reachable
|
||||
from **⌘K**:
|
||||
|
||||
| Spine item | Plain label | Maps to existing routes / apps |
|
||||
|-------------------|--------------------|--------------------------------|
|
||||
| Home | Home | `/home` (HomeCockpit) |
|
||||
| Chat | Chat | the agent runtime / chat |
|
||||
| Memory | Memory | `/memory` + per-workspace Memory tab |
|
||||
| Agents & tasks | Agents & tasks | `/agents` + `/automations` + `/approvals` |
|
||||
| Library | Library | `/artifacts` + `/files` + `/skills` |
|
||||
|
||||
**⌘K command bar** holds the full depth, each entry **plain-language with the
|
||||
technical term as a subtitle** (e.g. "Run a team of agents · waggle-dance · swarm";
|
||||
"Connect a tool · MCP servers"; "Launch a coding agent · Claude Code · Cursor").
|
||||
A **Pro mode** floats a "★ Pinned" group of power tools to the top of ⌘K.
|
||||
|
||||
Reference: `screens/ia.html` (working sidebar + ⌘K + Pro toggle).
|
||||
|
||||
---
|
||||
|
||||
## 5. The screens (what's in this bundle)
|
||||
|
||||
22 interactive references. Most use a top **segmented control** to switch
|
||||
variations or sub-views — that chrome is prototype-only; ship the chosen variation
|
||||
(noted per screen in §10) or wire the others as real routes/states.
|
||||
|
||||
| # | File | Screen(s) | Notes |
|
||||
|---|------|-----------|-------|
|
||||
| — | `Waggle Reimagined.html` | Concept index + narrative | embeds all app screens; coverage map at the end |
|
||||
| — | `Waggle Landing.html` | Marketing site (`apps/www`) | hero, BYO-agent, proof (SOTA), self-evolve, personas, pricing, footer |
|
||||
| 01 | `screens/home.html` | Home / Cockpit | **ship variation A (Editorial)**; B/C are alternates |
|
||||
| 02 | `screens/chat.html` | Chat / agent runtime | **ship variation B (split work-canvas)** as default |
|
||||
| 03 | `screens/workspace.html` | Single workspace | **ship variation A (Overview+tabs)**; Memory stays a tab |
|
||||
| 04 | `screens/workspaces.html` | All-workspaces index | grid + table; storage badges; search/filter |
|
||||
| 05 | `screens/ia.html` | Sidebar + ⌘K command bar | calm spine + Pro-pinned |
|
||||
| 06 | `screens/launcher.html` | Launcher (AI-OS) | external agents share workspace memory |
|
||||
| 07 | `screens/storage.html` | Storage & Files | virtual/local/team model + file browser |
|
||||
| 08 | `screens/surfaces.html` | Power surfaces | Tools · Automations · Approvals · Vault · Usage |
|
||||
| 09 | `screens/marketplace.html` | Marketplace | agent-searchable; **shared install state ("sync")**; inline-in-chat |
|
||||
| 10 | `screens/onboarding.html` | First-run (6 steps) | includes the **required model gate** |
|
||||
| 11 | `screens/settings.html` | Settings | progressive disclosure; **Models + failover pilot** |
|
||||
| 12 | `screens/evolution.html` | Skill evolution + diffusion | the second moat |
|
||||
| 13 | `screens/auth.html` | Auth (Clerk) | sign in/up, OTP verify, SSO |
|
||||
| 14 | `screens/billing.html` | Billing (Stripe) | plans → checkout → success → manage |
|
||||
| 15 | `screens/habit.html` | Engagement / habit loop | streak, compounding, variable reward, nudges |
|
||||
| 16 | `screens/appsurfaces.html` | Agents · Room · Artifacts · Mission Control · Timeline · Profile | six routes, one rail |
|
||||
| 17 | `screens/benchmark.html` | Benchmarks | capability matrix vs competitors + LoCoMo SOTA |
|
||||
| 18 | `screens/platform.html` | Platform & roadmap | Tauri desktop, boot, 404, "coming next" |
|
||||
|
||||
Per-screen detail (layout, components, copy, interactions, ship-this-variation) is
|
||||
in **§10**.
|
||||
|
||||
---
|
||||
|
||||
## 6. Global patterns (apply everywhere)
|
||||
|
||||
- **App chrome:** left **sidebar** (5 items + workspace switcher + user row), main
|
||||
column with a **`.shead`** (title + subtitle + primary action) over a scrolling
|
||||
body. Power surfaces and Settings use a **secondary left rail** inside the main column.
|
||||
- **Density & scale:** body 16px / 1.55; never below 12px. Section labels are
|
||||
11px mono, uppercase, `.12em` tracking, `--text-dim`, with a trailing hairline rule.
|
||||
- **One accent:** honey (`--honey`) is used sparingly — primary buttons, active nav,
|
||||
key numbers, focus. Semantics (work/intel/healthy/attention/risk) are **desaturated**
|
||||
and only for status, never decoration.
|
||||
- **Provenance everywhere:** any memory/fact/artifact shows a `⬡ source · when` line in
|
||||
mono / `--intel`. This is a core trust pattern — keep it.
|
||||
- **Cards:** `--surface` bg, `1px solid --line-soft`, radius `--r-lg` (18px),
|
||||
hover → `--honey-line` border + `translateY(-2px)` + `--shadow`.
|
||||
- **Buttons:** primary = honey bg / `#1a1407` text; ghost = `--surface` / `--line-strong`
|
||||
border, hover honey border. Radius 9–13px. See §7.
|
||||
- **Dark + light:** every screen supports both via `[data-theme]`. The toggle in the
|
||||
prototypes writes `localStorage['waggle-concept-theme']`; replace with the app theme
|
||||
provider. Both themes are warm (warm graphite ↔ warm paper) — see §7.
|
||||
- **Motion:** entrances `cubic-bezier(.16,1,.3,1)` ~.7s, gated so content is visible
|
||||
if JS/print/reduced-motion. Hover transitions .14–.18s. A live "breathing" dot
|
||||
(`@keyframes breathe`) marks active/live status. Honor `prefers-reduced-motion`.
|
||||
- **Focus:** `2px solid --honey`, `2px` offset. Keep keyboard access on ⌘K, OTP, forms.
|
||||
|
||||
---
|
||||
|
||||
## 7. Design tokens (source of truth: `styles/waggle.css`)
|
||||
|
||||
Map these onto the codebase's Tailwind theme + CSS variables. **Dark is default;**
|
||||
`[data-theme="light"]` overrides. All radii/type/shadow tokens are theme-independent.
|
||||
|
||||
### Colors — Dark (default)
|
||||
```
|
||||
--bg: #14110b (app background, warm near-black)
|
||||
--bg-2: #1a160f (recessed panels, rails)
|
||||
--surface: #1f1a12 (cards)
|
||||
--surface-2: #272117 (hover / insets)
|
||||
--surface-3: #322a1d (chips, icon tiles)
|
||||
--line: #38301f (default border)
|
||||
--line-soft: #2a2417 (subtle dividers)
|
||||
--line-strong: #4a4030 (emphasized border / scrollbar)
|
||||
--text: #f6f1e4 (primary)
|
||||
--text-2: #c8bfa9 (secondary)
|
||||
--text-muted: #948a73 (tertiary / body-muted)
|
||||
--text-dim: #6b6250 (labels, meta)
|
||||
```
|
||||
### Colors — Light (`[data-theme="light"]`)
|
||||
```
|
||||
--bg:#f7f1e4 --bg-2:#f1e9d8 --surface:#fffdf8 --surface-2:#f6efe0 --surface-3:#efe6d2
|
||||
--line:#e4d8be --line-soft:#ede3cd --line-strong:#d2c3a2
|
||||
--text:#211b11 --text-2:#5a5140 --text-muted:#847a64 --text-dim:#a99e85
|
||||
```
|
||||
### Accent — Honey (the one accent)
|
||||
```
|
||||
Dark: --honey:#e9a52c --honey-bright:#f6c45a --honey-deep:#c07e16
|
||||
Light: --honey:#b57d12 --honey-bright:#cf932a --honey-deep:#92620a
|
||||
--honey-wash: rgba(honey, .10) (tinted fills)
|
||||
--honey-line: rgba(honey, .28) (tinted borders)
|
||||
--honey-glow: 0 0 0 1px rgba(honey,.25), 0 8px 30px -10px rgba(honey,.35)
|
||||
On honey buttons, text/icon color is #1a1407.
|
||||
```
|
||||
### Semantics (desaturated; status only) — Dark / Light
|
||||
```
|
||||
--work #7aa6d6 / #3f72b0 (tasks, workspaces, blue)
|
||||
--intel #b196dd / #7d57b8 (memory/intelligence, violet) — also provenance
|
||||
--healthy #6cb78c / #3c8a5f (complete/healthy, sage)
|
||||
--attention#e9a52c / #b57d12 (attention/automation = honey)
|
||||
--risk #db8068 / #c0573c (risk/failure, terracotta)
|
||||
Each has a matching *-wash at ~.12 alpha for tinted chips/fills.
|
||||
```
|
||||
### Typography
|
||||
```
|
||||
--sans: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif
|
||||
--mono: 'JetBrains Mono', ui-monospace, monospace
|
||||
--serif: var(--sans) ← display intentionally uses the SAME grotesk (no book-serif)
|
||||
|
||||
Display headlines: Hanken Grotesk 600, letter-spacing -0.02 to -0.03em.
|
||||
- Hero (landing): clamp(40px, 5.6vw, 68px)
|
||||
- Section H2: clamp(28px, 3.8vw, 44px)
|
||||
- Screen H1: ~24–28px / 650
|
||||
Body: 14–16px / 400–550, line-height ~1.55.
|
||||
Labels/meta: 10–12px JetBrains Mono, uppercase, letter-spacing .10–.14em.
|
||||
Honey words in headlines are NOT italic — same weight, just --honey color.
|
||||
```
|
||||
### Radius / Shadow / Misc
|
||||
```
|
||||
--r-sm:8px --r:12px --r-lg:18px --r-xl:26px (pills/toggles: 999px)
|
||||
--shadow-sm: 0 1px 2px rgba(0,0,0,.4)
|
||||
--shadow: 0 4px 24px -8px rgba(0,0,0,.55), 0 1px 2px rgba(0,0,0,.4)
|
||||
--shadow-lg: 0 24px 60px -20px rgba(0,0,0,.7), 0 2px 8px rgba(0,0,0,.4)
|
||||
--shadow-pop:0 30px 80px -24px rgba(0,0,0,.8)
|
||||
(light theme has softer brown-tinted equivalents — see waggle.css)
|
||||
Hexagon motif: .hex { clip-path: polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%); }
|
||||
used for the brandmark, agent/workspace avatars, icon tiles.
|
||||
Honeycomb texture: .comb (inline SVG bg at ~.05 opacity) — very subtle, decorative only.
|
||||
Live dot: .dot-live → @keyframes breathe (2.4s).
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Cross-cutting behaviors to implement
|
||||
|
||||
- **⌘K command palette** (`screens/ia.html`): global hotkey (⌘/Ctrl-K) toggles a
|
||||
centered modal; fuzzy filter over grouped commands; arrow/Enter/Esc keyboard nav;
|
||||
groups = Jump to / Do / Power tools; Pro mode prepends a "★ Pinned" group. Each
|
||||
result = plain name + mono subtitle (technical term). Routes to real destinations.
|
||||
- **Theme:** dark default; persist user choice; both themes are warm. Use the app
|
||||
theme provider, not localStorage scaffolding.
|
||||
- **Marketplace install = one shared state** (`screens/marketplace.html`): a single
|
||||
install store drives the grid, the agent-suggestion picks, AND the inline-in-chat
|
||||
card — installing anywhere reflects everywhere ("sync"). Type-aware one-click flows:
|
||||
**skill** = instant Add; **connector** = "Connect" → auth → token to Vault;
|
||||
**MCP** = "Enable" tools. Each fires a confirmation toast + updates an
|
||||
"N in this workspace" bar.
|
||||
- **Onboarding model gate** (`screens/onboarding.html`, step 3): the flow **cannot
|
||||
reach "first task" without a working model** — either a validated provider API key
|
||||
or a detected/running local model. This mirrors the hard requirement that Waggle
|
||||
needs ≥1 working model. The same gate's permanent home is Settings → Models.
|
||||
- **Model failover pilot** (`screens/settings.html`): Primary → **Fallback on
|
||||
error** → **Budget/local model when daily budget hit**. Maps to the repo's
|
||||
`defaultModel / fallbackModel / budgetModel` + `budgetThreshold / dailyBudget`.
|
||||
- **Provenance** on every memory/artifact/fact (see §6).
|
||||
- **Approvals**: agent actions that touch external systems gate on a risk-badged
|
||||
approval card (inline in chat + an Approvals surface). "Always allow for this
|
||||
workspace" is an option.
|
||||
|
||||
---
|
||||
|
||||
## 9. The marketing site (`Waggle Landing.html` → `apps/www`)
|
||||
|
||||
Full content rewrite + new identity. Sections in order: nav → hero ("Your AI
|
||||
doesn't reset. Your work doesn't either.") → trust band → problem → 6 pillars →
|
||||
how-it-works (3 steps) → **Bring-your-own-agent** band (launch Claude Code/Cursor/Codex
|
||||
into shared memory) → **Proof** (LoCoMo SOTA: Waggle 87.66 vs Memori 81.95 /
|
||||
LangMem 78.05 / Mem0 62.47; +5.71pp, p<10⁻⁵; 92.75% single-hop; 100% local) →
|
||||
**Self-evolving** (skills improve 71→84→91% + diffuse across the hive) → personas
|
||||
(13) → pricing (Solo $0 / Pro $19 / Teams $49-seat + KVARK sovereign) → final CTA →
|
||||
footer. All copy is final; lift it verbatim. Reveal-on-scroll is JS-gated so content
|
||||
is always visible without JS (keep that property for SEO/no-JS).
|
||||
|
||||
**Numbers come from the real benchmark docs / `hive-mind` repo. Keep them accurate;
|
||||
if the public claim must stay conservative until the SOTA PR merges, gate the headline.**
|
||||
|
||||
---
|
||||
|
||||
## 10. Per-screen specifications
|
||||
|
||||
See **`SCREENS.md`** in this folder for the full per-screen breakdown (layout,
|
||||
components, exact copy, interactions, and **which variation to ship**).
|
||||
|
||||
---
|
||||
|
||||
## 11. Assets
|
||||
|
||||
- **No raster assets / no external images.** All iconography is **inline SVG**
|
||||
(1.7–1.8 stroke, round caps) — reuse the codebase's icon set (e.g. lucide) matched
|
||||
to these shapes. The brandmark is the letter **W** in a `.hex` clip-path over a
|
||||
honey gradient. The honeycomb texture is an inline SVG data-URI (`.comb` in
|
||||
`waggle.css`).
|
||||
- **Fonts:** Hanken Grotesk + JetBrains Mono (Google Fonts). Self-host in the Tauri
|
||||
app for offline use.
|
||||
- **Competitor / provider names** (Stripe, Clerk, Salesforce, Claude, GPT, etc.) are
|
||||
shown as mono text/initials, not logos — swap in real logos per each brand's
|
||||
guidelines if desired.
|
||||
|
||||
---
|
||||
|
||||
## 12. Tech mapping (existing monorepo)
|
||||
|
||||
```
|
||||
apps/web React + TS + Vite + Tailwind + shadcn/ui + React Router → all app screens
|
||||
apps/www Next.js marketing site → Waggle Landing.html
|
||||
apps/browser-ext → roadmap (beta)
|
||||
packages/* core / memory (hive-mind) / agent runtime / connectors / mcp
|
||||
Desktop Tauri (Windows + macOS) → screens/platform.html
|
||||
Auth Clerk → screens/auth.html
|
||||
Billing Stripe → screens/billing.html
|
||||
```
|
||||
Recommended order: **(1)** tokens → Tailwind theme + theme provider; **(2)** app
|
||||
shell (sidebar + ⌘K); **(3)** Home, Chat, Workspace; **(4)** Marketplace + install
|
||||
store; **(5)** Settings (models/failover) + Onboarding gate; **(6)** the remaining
|
||||
surfaces; **(7)** Auth + Billing; **(8)** `apps/www` landing. Ship dark first.
|
||||
|
||||
---
|
||||
|
||||
## 13. Files in this bundle
|
||||
```
|
||||
design_handoff_waggle_app/
|
||||
├── README.md ← this file
|
||||
├── SCREENS.md ← per-screen specifications
|
||||
├── DESIGN_POV.md ← designer's strategic contributions (incl. the built Trust layer)
|
||||
├── screenshots/ ← reference captures (1 per screen) + index
|
||||
│ ├── README.md
|
||||
│ └── 00–19 *.png
|
||||
└── design-files/
|
||||
├── Waggle Reimagined.html ← concept index (open first)
|
||||
├── Waggle Landing.html ← marketing site
|
||||
├── styles/waggle.css ← design tokens (source of truth)
|
||||
└── screens/*.html ← 19 app-screen references
|
||||
```
|
||||
Open `design-files/Waggle Reimagined.html` in a browser and use its top nav to walk
|
||||
the whole concept; toggle dark/light with the ☾ button; try ⌘K inside the Navigation
|
||||
section.
|
||||
371
docs/design_handoff_waggle_app/SCREENS.md
Normal file
@@ -0,0 +1,371 @@
|
||||
# SCREENS.md — Per-screen specifications
|
||||
|
||||
Companion to `README.md`. Every screen shares the tokens in §7 and the global
|
||||
patterns in §6 of the README; only screen-specific detail is below. **"Ship"** notes
|
||||
which variation is the chosen default (others are alternates to wire as routes/state
|
||||
or drop).
|
||||
|
||||
Prototype chrome to ignore when porting: the top **segmented control** (variation
|
||||
switcher), the **☾ theme button**, and the **"· variation"** labels — all
|
||||
demonstration-only.
|
||||
|
||||
---
|
||||
|
||||
## 01 · Home / Cockpit — `home.html` → **Ship: Variation A (Editorial)**
|
||||
|
||||
**Purpose:** the daily landing. Opens with one human sentence, tells the overnight
|
||||
story, offers one obvious next move.
|
||||
|
||||
**Layout:** single centered column, max-width 920px, 46px top padding.
|
||||
- **Greeting:** mono date row (`--honey`) with a live dot + a **🔥 streak chip**
|
||||
(right-aligned pill, `--honey-wash` bg, `--honey-line` border). H1 = Hanken 600,
|
||||
clamp(34→52px); the word "ahead" is honey (not italic).
|
||||
- **Overnight hero card:** radius `--r-xl`, gradient `--surface → --surface-2`,
|
||||
`--shadow`, a soft honey radial glow top-right. Mono eyebrow "While you slept"
|
||||
(`--intel` dot). Large statement line (Hanken 600, clamp 21→28px) with honey key
|
||||
numbers. Row of "run chips" (status dot + label) below.
|
||||
- **"Pick up where you left off":** 2-col grid of workspace cards (hex avatar,
|
||||
title, time, summary, "Continue →", optional status badge).
|
||||
- **"Waggle suggests":** stacked action rows (tinted icon tile, title, sub, arrow
|
||||
that slides on hover).
|
||||
- **Ask bar:** pill, full-width, honey "+" icon, "⌘K" hint, honey send button.
|
||||
|
||||
**Copy (exact):** "Good morning, Mara." / "You're **ahead** of yesterday." ·
|
||||
"While you slept" · "Waggle finished the **Q2 competitor teardown**, folded **14 new
|
||||
memories** into the hive, and ran into **one snag** worth a look." · run chips:
|
||||
"Teardown drafted · 9 competitors", "14 memories consolidated", "2 artifacts created",
|
||||
"1 export failed".
|
||||
|
||||
**Variations:** A Editorial (ship) · B Focus (single centered ask + resume list) ·
|
||||
C Operator (dense dashboard: overnight stats, active workspaces, up-next, agents,
|
||||
a risk alert for the failed Salesforce export).
|
||||
|
||||
---
|
||||
|
||||
## 02 · Chat / agent runtime — `chat.html` → **Ship: Variation B (Split work canvas)**
|
||||
|
||||
**Purpose:** the core work surface. Conversation leads; the agent's thinking, tool
|
||||
calls, memory writes, and approvals reveal progressively; a live artifact builds in a
|
||||
side canvas.
|
||||
|
||||
**Layout:** context header (workspace hex + name + "142 memories · 9 sources" +
|
||||
**model pill** "auto · Claude Sonnet" + memory icon) → scrolling thread (max 760px,
|
||||
narrows to ~620px when canvas open) → composer. **Variation B** adds a right **work
|
||||
canvas** (~42% width) showing a live-drafting `teardown.md`.
|
||||
|
||||
**Thread components:**
|
||||
- **User message:** `--surface` bubble, asymmetric radius `4px 14px 14px 14px`.
|
||||
- **Bot message:** hex "W" avatar; "Waggle · Analyst · Claude Sonnet" meta.
|
||||
- **Activity stream** (the "magic"): collapsible card, `--bg-2`, violet spark icon.
|
||||
Header "Worked across memory, web & files · 6 steps · 38s" + chevron. Steps each
|
||||
have a colored dot, text, and a **provenance pill** (`⬡ mem://hive · provenance
|
||||
kept`, mono, `--intel`). Default-open on the active turn.
|
||||
- **Approval card:** `--honey-wash` bg, attention border, warning icon, "Approve
|
||||
before I leave your machine", mono target `Salesforce › Q2 Pricing`, "Approve &
|
||||
export" / "Not now".
|
||||
|
||||
**Composer:** rounded box, textarea, attach / "Persona: Analyst" / Tools chips, mono
|
||||
"⏎ send · ⌘K commands" hint, honey send.
|
||||
|
||||
**Interaction:** clicking an activity header toggles its steps. Variation B canvas
|
||||
has a blinking honey type-cursor on the live draft.
|
||||
|
||||
---
|
||||
|
||||
## 03 · Workspace — `workspace.html` → **Ship: Variation A (Overview + tabs)**
|
||||
|
||||
**Purpose:** the calm home for one project; makes memory tangible.
|
||||
|
||||
**Layout:** header (breadcrumb, 46px hex avatar, title, meta row "1 agent live · 142
|
||||
memories · 9 sources · updated 2h", "Memory"/"Continue" buttons) → **tab bar**
|
||||
(Overview · Chat 3 · Memory 142 · Artifacts 7 · Files 12 · Team 4; honey underline on
|
||||
active) → content. Overview = 2-col grid (1.7fr / 1fr):
|
||||
- **Left:** summary card; **"What Waggle knows"** (fact rows, each with a hex check
|
||||
tile + `⬡ source · when` provenance); **"Recent work"** (artifact rows, ext tile +
|
||||
name + provenance + time).
|
||||
- **Right:** Status card (agent live, model, memories +6 today, 3 to review); Up next;
|
||||
Team (avatar rows).
|
||||
|
||||
**Memory stays a tab** here (do NOT make the graph the default). Variation B
|
||||
(Memory-forward, with the knowledge-graph viz) is an **alternate**, not the default.
|
||||
|
||||
---
|
||||
|
||||
## 04 · All workspaces — `workspaces.html`
|
||||
|
||||
**Purpose:** answers "where are all my workspaces?" The full shelf (Home = your day;
|
||||
this = everything).
|
||||
|
||||
**Layout:** header ("Workspaces" + "New workspace"), toolbar (search "…or ask the
|
||||
agent to find one" + storage filter pills All/Local/Virtual/Team), then **Grid** or
|
||||
**Table** (segmented). Cards: hex avatar, title, **storage badge** (Local=honey,
|
||||
Virtual=intel, Team=healthy), summary, meta (memories, "agent live", "N to review",
|
||||
"Open →"). 8 sample workspaces across all three storage types. A note explains it's
|
||||
reachable from rail, ⌘K, or any workspace switcher.
|
||||
|
||||
---
|
||||
|
||||
## 05 · Sidebar + ⌘K — `ia.html`
|
||||
|
||||
**Purpose:** the calm spine + the command bar holding all depth.
|
||||
|
||||
**Sidebar:** workspace switcher pill (hex + name + chevron) → 5 nav items (Home, Chat,
|
||||
Memory, Agents & tasks [badge 2], Library) with honey active state (left honey bar +
|
||||
`--honey-wash`) → "Everything else" → **⌘K tile** → spacer → user row.
|
||||
**Pro variation** inserts a "Pinned · power tools" group (Agent swarm, Connectors,
|
||||
Approvals [badge]).
|
||||
|
||||
**⌘K palette:** centered modal over a dim/blur scrim; search input + "esc" chip;
|
||||
grouped results (Jump to / Do / Power tools), each = icon + **plain name** + mono
|
||||
**subtitle** (technical term) + optional shortcut. First result auto-selected.
|
||||
**Pro mode** prepends "★ Pinned · Pro" (honey group header + star markers). Hotkey
|
||||
⌘/Ctrl-K toggles; Esc closes; clicking a result routes + closes.
|
||||
|
||||
**Key copy patterns:** "Run a team of agents · waggle-dance · swarm" · "Connect a
|
||||
tool · MCP servers · 21 tools" · "Launch a coding agent · Claude Code · Cursor · Codex"
|
||||
· "Tune the agent · GEPA optimizer" · "Secrets · encrypted vault".
|
||||
|
||||
---
|
||||
|
||||
## 06 · Launcher (AI-OS) — `launcher.html`
|
||||
|
||||
**Purpose:** detect & launch external coding agents **into a workspace's shared
|
||||
memory**. (The shipped app calls this "minimal-viable" — this makes it first-class.)
|
||||
|
||||
**Variation A (Launch):** header + platform pill "⌘ macOS · 7 tools scanned"; an
|
||||
optional **launch-with-a-task** prompt box (with "Sent to: Claude Code, Cursor ·
|
||||
Ignored by: Claude Desktop"); **Detected** tool cards (Claude Code [Hooks active,
|
||||
Running], Cursor, Codex [hooks soon], Claude Desktop [no-prompt]) each with
|
||||
installed/version/path, badges, and **Launch in workspace / Stop / Install·Verify
|
||||
hooks** actions; **Not installed** group (Hermes, OpenClaw); a **"Running now"** panel
|
||||
(PID + duration + Stop).
|
||||
|
||||
**Variation B (How memory is shared):** a 3-node flow — `Claude Code →
|
||||
WAGGLE_WORKSPACE_ID → 5 hive-mind hooks → your hive` — plus three cards (recalls on
|
||||
start / commits as it works / reversible & local) and a provenance example
|
||||
`⬡ remembered from Claude Code · 14:22 · session a1f9`.
|
||||
|
||||
**Implementation note:** the env var `WAGGLE_WORKSPACE_ID` and the SessionStart/Stop/
|
||||
PreCompact/etc. hooks are real repo concepts — wire to the actual launcher service.
|
||||
|
||||
---
|
||||
|
||||
## 07 · Storage & Files — `storage.html`
|
||||
|
||||
**Purpose:** make the filesystem legible — where a workspace lives (virtual/local/team).
|
||||
|
||||
**Variation A (Where it lives):** a "live location" card (hex avatar, "Local · private"
|
||||
pill) showing the real on-disk tree (`~/Waggle/workspaces/competitive-intelligence/`
|
||||
→ `hive.mind` 3.2 MB · 142 memories, `files/`, `artifacts/`, `workspace.json`); then
|
||||
**three storage-type cards** — Virtual (Waggle-managed, intel), Local (a folder on
|
||||
your machine, honey, "this one"), Team (shared/synced, healthy) — each with a privacy
|
||||
pill; then a local-first reassurance.
|
||||
|
||||
**Variation B (Files):** classic browser — left folder tree, breadcrumb + New
|
||||
folder/Upload, a file table with a **Source/provenance column** (incl. `board-brief.md`
|
||||
"made by Claude Code"), and a status bar naming the exact local path.
|
||||
|
||||
**Maps to repo `StorageType = 'virtual' | 'local' | 'team'`.**
|
||||
|
||||
---
|
||||
|
||||
## 08 · Power surfaces — `surfaces.html`
|
||||
|
||||
**Purpose:** the long tail on one consistent template, behind ⌘K. Left rail switches
|
||||
**Tools · Automations · Approvals · Vault · Usage**; main = `.shead` + rows.
|
||||
- **Tools:** connected integrations (Salesforce/Slack/GitHub), MCP servers (21 tools),
|
||||
available connectors.
|
||||
- **Automations:** scheduled jobs with **working enable/pause toggles**; the failed
|
||||
"Q2 pipeline sync → Salesforce" (auth expired) with "Fix & retry".
|
||||
- **Approvals:** risk-badged action cards (Approve/Deny/Always-allow) + recently decided.
|
||||
- **Vault:** masked keys (`sk-ant-•••3a9f`) with Rotate/Reveal/Renew; "encrypted,
|
||||
never shown to a model".
|
||||
- **Usage:** spend stat cards, per-model bars, per-workspace breakdown, budget.
|
||||
|
||||
Build ONE row/card/toggle component set and reuse — the consistency is the usability fix.
|
||||
|
||||
---
|
||||
|
||||
## 09 · Marketplace — `marketplace.html`
|
||||
|
||||
**Purpose:** skills + connectors + MCP as **one shelf**, agent-searchable, super simple.
|
||||
|
||||
**Variation A (Browse & ask):** centered **agent-search bar** ("Describe what you want
|
||||
to do…" → "Ask the agent"); example chips; **agent-suggestion box** that recommends a
|
||||
connector + skill + tool, each with a "why" reason and an install button; an
|
||||
**"N in this workspace" bar** (chips); category filter (All/Skills/Connectors/MCP);
|
||||
card grid (kind badge, name, desc, install count, Add button).
|
||||
|
||||
**Variation B (Inline in chat):** the same picker surfaced mid-conversation — Waggle
|
||||
offers a missing Salesforce connector with a vault-aware approval ("token goes to your
|
||||
vault"), then shows the connected follow-up.
|
||||
|
||||
**CRITICAL — shared install state ("sync"):** one store powers the grid, the agent
|
||||
picks, AND the inline card. Type-aware one-click flows with progress→done micro-states:
|
||||
**skill** Add→Adding…→Added (instant); **connector** Connect→Signing in…→Connected
|
||||
(~1.1s, token→vault); **MCP** Enable→Enabling…→Enabled. Each fires a toast and updates
|
||||
the count bar. Installing in any view reflects in all of them.
|
||||
|
||||
---
|
||||
|
||||
## 10 · Onboarding — `onboarding.html`
|
||||
|
||||
**Purpose:** ≤2-minute first-run, ending **inside the work**, not on a blank screen.
|
||||
|
||||
**6 steps** (full-screen takeover, progress bar, Back/Skip/Continue):
|
||||
1. **Welcome** — "The workspace that remembers." local-first reassurance.
|
||||
2. **About you** — name + role (single-select chips) + team size.
|
||||
3. **Give it a brain (MODEL GATE)** — two tabs: **API key** (provider chips +
|
||||
live-validated key field, "✓ valid", "encrypted in your local vault") OR **local
|
||||
model** (detected Qwen running / Llama to pull). **Hard gate: cannot proceed to
|
||||
step 6 without one.**
|
||||
4. **Import** — ChatGPT / Claude / Cursor / Start fresh (imported locally).
|
||||
5. **Template** — Research / Strategy / Engineering / Sales / Writing / Custom.
|
||||
6. **First task** — ask field + suggested tasks → opens straight into the workspace.
|
||||
|
||||
The model gate is the single most important time-to-first-value fix — its permanent
|
||||
home is Settings → Models (screen 11).
|
||||
|
||||
---
|
||||
|
||||
## 11 · Settings — `settings.html`
|
||||
|
||||
**Purpose:** calm, progressive-disclosure settings; **Models leads** with failover.
|
||||
|
||||
**Layout:** left rail (General · **Models** · Permissions · Plan · Team · Backup ·
|
||||
Advanced) + a top-right **"Show: Essential / Standard / Everything"** control —
|
||||
Advanced only appears at "Everything" (progressive disclosure).
|
||||
|
||||
**Models (lead):** a banner confirming ≥1 working model; the **"Model pilot" failover
|
||||
chain** — **Primary** (Claude Sonnet, key set) → trigger "if it errors" → **Fallback**
|
||||
(GPT-4o) → trigger "when you hit your daily budget" → **Budget** (Qwen local, running);
|
||||
a **daily budget** input (switch at 80%); read-only provider-key list (manage in
|
||||
Vault); local models list. **Maps to `defaultModel/fallbackModel/budgetModel` +
|
||||
`budgetThreshold/dailyBudget`.**
|
||||
|
||||
**Other tabs:** General (theme cards, language, local-first on-always, erase data);
|
||||
Permissions (default approval level radios + always-require list); Plan (Pro trial +
|
||||
upgrade paths + KVARK); Team (connect a team server); Backup (export/import/encrypted
|
||||
backup); Advanced (dev mode, telemetry, prompt shape, debug).
|
||||
|
||||
---
|
||||
|
||||
## 12 · Skill evolution + diffusion — `evolution.html`
|
||||
|
||||
**Purpose:** the second moat — skills improve themselves AND spread.
|
||||
|
||||
**Variation A (Evolution):** a skill card ("Competitor teardown") with a **version
|
||||
ladder** v1 71% → v2 84% → v3 91% (best), each a scored bar + note; the v3 carries
|
||||
"GEPA optimized · judged by 3 models". A "how it improves" explainer (optimizer
|
||||
proposes, 3-model judge scores, ships only if it wins, old versions kept).
|
||||
|
||||
**Variation B (Diffusion):** two maps — a **skill** propagating from Research-synth to
|
||||
2 agents + 1 teammate; a **tool recipe** (Salesforce export config) spreading across 2
|
||||
workspaces. Signals `⬡ waggle-dance · skill_share` / `model_recipe`. "Suggest-then-
|
||||
adopt; secrets stay per-vault."
|
||||
|
||||
---
|
||||
|
||||
## 13 · Auth (Clerk) — `auth.html`
|
||||
|
||||
**Purpose:** simple sign-in, with honest "account is optional / local-first" framing.
|
||||
|
||||
**Layout:** split — left brand panel ("Your work follows you, everywhere." + trust
|
||||
lines: "An account is optional — Waggle runs fully local without one") / right form.
|
||||
**States:** Sign in (Google/Apple SSO + email/password) · Sign up (with local-first
|
||||
note) · **Verify** (6-box OTP, auto-advance, backspace nav) · **SSO/enterprise** (SAML/
|
||||
SCIM note → Teams/KVARK). Continue routes to Home. Build with Clerk components themed
|
||||
to the tokens.
|
||||
|
||||
---
|
||||
|
||||
## 14 · Billing (Stripe) — `billing.html`
|
||||
|
||||
**Purpose:** frictionless upgrade. **4 states (segmented):**
|
||||
- **Plans:** monthly/annual toggle (−20%), 3 cards (Solo current / **Pro popular** /
|
||||
Teams), honey "Most popular".
|
||||
- **Checkout:** 2-col — card form (email, card 4242…, expiry/CVC, name, country,
|
||||
"encrypted & secure", "Powered by Stripe") + **order summary** (plan row, line items,
|
||||
promo, trial-aware "Due today $19", "won't be charged until …").
|
||||
- **Success:** healthy check ring, "You're Pro.", receipt, "Start using Pro" / "Manage".
|
||||
- **Manage:** current plan, billing cycle (switch to annual), payment method (VISA
|
||||
···4242, Update), next charge, **invoices** (Paid + PDF), change plan / cancel.
|
||||
|
||||
Use Stripe Checkout/Customer Portal where possible; theme to tokens. Pricing: Solo $0
|
||||
/ Pro $19 / Teams $49-seat.
|
||||
|
||||
---
|
||||
|
||||
## 15 · Habit loop — `habit.html`
|
||||
|
||||
**Purpose:** document the engagement layer — "momentum, not manipulation."
|
||||
|
||||
**Content:** a 4-stage loop (Trigger → Action → Variable reward → Investment); then 4
|
||||
concrete mechanics — **daily streak** (week dots + "12-day streak"), **compounding
|
||||
memory** ("142 · +14 this week · top 8% by depth"), **while you were away** (variable
|
||||
reward chips), **gentle nudges** (earned, not spam); closing **ethics note** (anchored
|
||||
to real value, no dark patterns, all toggle-off-able). The **streak chip also appears
|
||||
on Home** (screen 01). This is a spec/principles screen — implement the mechanics in
|
||||
Home/notifications, not as a standalone page.
|
||||
|
||||
---
|
||||
|
||||
## 16 · App surfaces — `appsurfaces.html`
|
||||
|
||||
Six routes on one rail (ship as real routes):
|
||||
- **Agents** — Working now / Idle / "Run a team of agents" (swarm). Status badges.
|
||||
- **Room** — work alongside agents **live**: shared stage of turns + participants
|
||||
panel (you host, agents live, teammate invited, "everyone shares this memory").
|
||||
- **Artifacts** — 3-col card grid with ext tiles + **provenance** (incl. "made by
|
||||
Claude Code").
|
||||
- **Mission Control** — hive health: stat row + local services list (memory engine,
|
||||
agent runtime, local model, Salesforce sync [auth expired], team sync [not connected]).
|
||||
- **Timeline** — one chronological activity stream with source tags.
|
||||
- **Profile** — what Waggle knows about you: name/role, "how I like to work" chips
|
||||
(every agent reads these), known-facts list, persona chips. This powers agent behavior.
|
||||
|
||||
---
|
||||
|
||||
## 17 · Benchmarks — `benchmark.html`
|
||||
|
||||
**Purpose:** honest positioning + the one real lab result. **2 views:**
|
||||
- **Capabilities:** category framing ("They automate tasks. Waggle remembers you.") —
|
||||
two cards (Task agents = Claude Code/Codex/Cowork/Hermes/Odysseus vs Waggle = memory
|
||||
layer + workspace) + an **11-row capability matrix** (Waggle column honey-highlighted;
|
||||
●/◐/○). Deliberately gives competitors ● on "deep terminal coding" (the last row) —
|
||||
credible, not stacked. Labeled "a positioning view, not a lab benchmark."
|
||||
- **Memory SOTA:** the LoCoMo bars (87.66 / 81.95 / 78.05 / 62.47) + stats (+5.71pp,
|
||||
p<10⁻⁵; 92.75% single-hop; 100% local 58–83ms) + method/caveat.
|
||||
|
||||
Keep the matrix honest and the numbers accurate to the `hive-mind` benchmark.
|
||||
|
||||
---
|
||||
|
||||
## 18 · Platform & roadmap — `platform.html`
|
||||
|
||||
**Purpose:** the Tauri desktop story + roadmap. **4 views:**
|
||||
- **Desktop (now):** a desktop-window mock with **macOS ↔ Windows** title-bar toggle
|
||||
(traffic lights vs min/max/close), a mini app inside; spec tiles (~12 MB, local,
|
||||
auto-update signed/notarized, Win·Mac, Linux soon).
|
||||
- **Boot:** honey hex mark (pulsing), "Warming the hive…", checklist (memory engine
|
||||
ready, local model online, loading workspaces [spinner], restoring session).
|
||||
- **Coming next:** channel cards — Desktop (now) · Browser extension (beta) ·
|
||||
**Messaging (WhatsApp/Telegram/iMessage) — coming next** · **Mobile (iOS/Android) —
|
||||
coming next**.
|
||||
- **404:** big honey "404", "This cell of the hive is empty.", back-to-Home / ⌘K.
|
||||
|
||||
---
|
||||
|
||||
## Ship-variation summary
|
||||
|
||||
| Screen | Ship this | Alternates (wire as routes/state or drop) |
|
||||
|--------|-----------|-------------------------------------------|
|
||||
| Home | A Editorial | B Focus, C Operator |
|
||||
| Chat | B Split work-canvas | A Conversation-first |
|
||||
| Workspace | A Overview+tabs (Memory = tab) | B Memory-forward graph |
|
||||
| Workspaces | Grid default | Table |
|
||||
| Launcher | A Launch (B = explainer) | — |
|
||||
| Storage | A Where-it-lives + B Files (both real) | — |
|
||||
| Marketplace | A Browse+ask + B inline (both real) | — |
|
||||
| Settings | Models-first, Essential default | Standard/Everything levels |
|
||||
| Evolution / Benchmark / Platform | both views are real tabs | — |
|
||||
648
docs/design_handoff_waggle_app/design-files/Waggle Landing.html
Normal file
@@ -0,0 +1,648 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle — the AI workspace that remembers</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="styles/waggle.css">
|
||||
<style>
|
||||
html { scroll-behavior: smooth; }
|
||||
body { overflow-x: hidden; }
|
||||
.container { max-width: 1180px; margin: 0 auto; padding: 0 28px; }
|
||||
|
||||
/* ── Nav ─────────────────────────────────────────────────────── */
|
||||
.nav {
|
||||
position: fixed; inset: 0 0 auto 0; z-index: 60; height: 66px;
|
||||
display: flex; align-items: center; gap: 26px;
|
||||
padding: 0 28px;
|
||||
background: color-mix(in srgb, var(--bg) 72%, transparent);
|
||||
backdrop-filter: blur(20px) saturate(1.4); -webkit-backdrop-filter: blur(20px) saturate(1.4);
|
||||
border-bottom: 1px solid transparent; transition: border-color .3s, background .3s;
|
||||
}
|
||||
.nav.scrolled { border-color: var(--line-soft); }
|
||||
.brand { display: flex; align-items: center; gap: 11px; }
|
||||
.brand .mark { width: 30px; height: 33px; display: grid; place-items: center; background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); color: #1a1407; font-weight: 800; font-size: 15px; box-shadow: var(--honey-glow); }
|
||||
.brand b { font-size: 18px; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.nav .links { display: flex; gap: 4px; margin-left: 18px; }
|
||||
.nav .links a { font-size: 14px; font-weight: 500; color: var(--text-muted); text-decoration: none; padding: 8px 13px; border-radius: 8px; transition: .15s; }
|
||||
.nav .links a:hover { color: var(--text); background: var(--surface-2); }
|
||||
.nav .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.signin { font-size: 14px; font-weight: 600; color: var(--text-2); text-decoration: none; padding: 9px 14px; border-radius: 9px; }
|
||||
.signin:hover { color: var(--text); }
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
|
||||
font-family: var(--sans); font-size: 14.5px; font-weight: 650; letter-spacing: -0.01em;
|
||||
padding: 11px 20px; border-radius: 11px; text-decoration: none; border: 1px solid transparent; transition: .16s;
|
||||
}
|
||||
.btn-primary { background: var(--honey); color: #1a1407; box-shadow: var(--honey-glow); }
|
||||
.btn-primary:hover { background: var(--honey-bright); transform: translateY(-1px); }
|
||||
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--line-strong); }
|
||||
.btn-ghost:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.btn-lg { padding: 15px 26px; font-size: 16px; border-radius: 13px; }
|
||||
.themebtn { width: 38px; height: 38px; border-radius: 10px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; display: grid; place-items: center; }
|
||||
.themebtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
/* ── Reveal (JS-gated: content shows by default; only hidden once JS confirms) ── */
|
||||
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s cubic-bezier(.16,1,.3,1), transform .7s cubic-bezier(.16,1,.3,1); }
|
||||
.js .reveal.in { opacity: 1; transform: none; }
|
||||
@media (prefers-reduced-motion: reduce) { .js .reveal { opacity: 1; transform: none; transition: none; } }
|
||||
|
||||
/* ── Hero ────────────────────────────────────────────────────── */
|
||||
.hero { padding: 150px 0 90px; position: relative; overflow: hidden; }
|
||||
.hero .comb { position: absolute; inset: 0; opacity: .5; pointer-events: none; mask-image: radial-gradient(120% 90% at 70% 10%, black, transparent 75%); }
|
||||
.hero-grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; position: relative; }
|
||||
.eyebrow { display: inline-flex; align-items: center; gap: 9px; font-size: 13px; font-weight: 600; color: var(--honey); letter-spacing: -0.005em; margin-bottom: 22px; padding: 6px 13px 6px 11px; border: 1px solid var(--honey-line); border-radius: 999px; background: var(--honey-wash); }
|
||||
.eyebrow .dot { background: var(--honey); }
|
||||
h1.hero-h { font-size: clamp(40px, 5.6vw, 68px); font-weight: 600; line-height: 1.02; letter-spacing: -0.03em; margin: 0 0 24px; text-wrap: balance; }
|
||||
h1.hero-h em { font-style: normal; color: var(--honey); }
|
||||
.hero p.sub { font-size: clamp(17px, 1.7vw, 20px); line-height: 1.55; color: var(--text-2); max-width: 36em; margin: 0 0 32px; }
|
||||
.hero .cta-row { display: flex; flex-wrap: wrap; gap: 13px; margin-bottom: 26px; }
|
||||
.chips { display: flex; flex-wrap: wrap; gap: 9px; }
|
||||
.chips .chip { display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 12px; color: var(--text-muted); padding: 6px 11px; border-radius: 8px; background: var(--surface); border: 1px solid var(--line-soft); }
|
||||
.chips .chip .dot { background: var(--healthy); }
|
||||
|
||||
/* ── Hero hive visual ────────────────────────────────────────── */
|
||||
.hive { position: relative; aspect-ratio: 1 / 1; max-width: 460px; margin: 0 auto; width: 100%; }
|
||||
.hive .ring { position: absolute; inset: 0; }
|
||||
.hexcell {
|
||||
position: absolute; transform: translate(-50%, -50%);
|
||||
display: grid; place-items: center; text-align: center;
|
||||
}
|
||||
.hexcell .hx { background: var(--surface); border: 1px solid var(--line); display: grid; place-items: center; gap: 2px; box-shadow: var(--shadow); }
|
||||
.hexcell.core .hx { width: 168px; height: 188px; background: linear-gradient(150deg, var(--surface-2), var(--surface)); border-color: var(--honey-line); box-shadow: var(--honey-glow), var(--shadow-lg); }
|
||||
.hexcell.core .label { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--honey); }
|
||||
.hexcell.core .big { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.05; }
|
||||
.hexcell.core .meta { font-family: var(--mono); font-size: 10px; color: var(--text-dim); margin-top: 4px; }
|
||||
.hexcell.sat .hx { width: 104px; height: 116px; }
|
||||
.hexcell.sat .prov { font-size: 13px; font-weight: 650; letter-spacing: -0.01em; }
|
||||
.hexcell.sat .act { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; margin-top: 3px; }
|
||||
.hexcell.sat .act.recall { color: var(--work); }
|
||||
.hexcell.sat .act.commit { color: var(--healthy); }
|
||||
.hive svg.wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
||||
.wire { stroke: var(--line-strong); stroke-width: 1.4; fill: none; }
|
||||
.flow { stroke: var(--honey); stroke-width: 2.4; fill: none; stroke-linecap: round; stroke-dasharray: 5 190; opacity: .85; animation: flow 3.4s linear infinite; }
|
||||
@keyframes flow { to { stroke-dashoffset: -195; } }
|
||||
@media (prefers-reduced-motion: reduce) { .flow { animation: none; opacity: .4; } }
|
||||
.hive .winlabel { position: absolute; font-family: var(--mono); font-size: 10px; color: var(--text-dim); display:flex; align-items:center; gap:6px; }
|
||||
|
||||
/* ── Section scaffold ────────────────────────────────────────── */
|
||||
section.band { padding: 92px 0; position: relative; }
|
||||
.sec-eyebrow { font-family: var(--mono); font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--honey); display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
|
||||
.sec-eyebrow::before { content: ''; width: 22px; height: 1px; background: var(--honey-line); }
|
||||
h2.sec-h { font-size: clamp(28px, 3.8vw, 44px); font-weight: 600; line-height: 1.08; letter-spacing: -0.025em; margin: 0; text-wrap: balance; }
|
||||
h2.sec-h em { font-style: normal; color: var(--honey); }
|
||||
.sec-head { max-width: 30ch; }
|
||||
.sec-head.wide { max-width: 46ch; }
|
||||
.sec-sub { font-size: 18px; color: var(--text-2); line-height: 1.55; margin: 18px 0 0; max-width: 56ch; }
|
||||
|
||||
/* ── Trust band ──────────────────────────────────────────────── */
|
||||
.trust { border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); padding: 30px 0; background: var(--bg-2); }
|
||||
.trust .row { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; justify-content: space-between; }
|
||||
.trust .badge { font-size: 14.5px; color: var(--text-2); display: flex; align-items: center; gap: 11px; font-weight: 500; }
|
||||
.trust .badge .mk { width: 22px; height: 25px; background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); flex: none; }
|
||||
.trust .signals { display: flex; gap: 22px; flex-wrap: wrap; }
|
||||
.trust .signals span { font-size: 13px; color: var(--text-muted); display: inline-flex; align-items: center; gap: 8px; }
|
||||
.trust .signals .dot { background: var(--honey); }
|
||||
|
||||
/* ── Problem / comparison ────────────────────────────────────── */
|
||||
.problem { text-align: center; }
|
||||
.problem .sec-eyebrow { justify-content: center; }
|
||||
.problem .sec-eyebrow::before { display: none; }
|
||||
.problem h2 { margin: 0 auto; max-width: 18ch; }
|
||||
.problem .sec-sub { margin: 22px auto 0; }
|
||||
|
||||
/* ── Pillars ─────────────────────────────────────────────────── */
|
||||
.pillars-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 48px; }
|
||||
.pillar { padding: 28px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); transition: .2s; position: relative; overflow: hidden; }
|
||||
.pillar:hover { border-color: var(--honey-line); transform: translateY(-3px); box-shadow: var(--shadow); }
|
||||
.pillar .pn { display:flex; align-items:center; gap:11px; margin-bottom: 16px; }
|
||||
.pillar .pn .ic { width: 38px; height: 42px; flex: none; display: grid; place-items: center; background: var(--surface-2); border: 1px solid var(--line); }
|
||||
.pillar .pn .ic svg { width: 19px; height: 19px; stroke: var(--honey); fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.pillar .pn .num { font-family: var(--mono); font-size: 11px; color: var(--text-dim); letter-spacing: .12em; }
|
||||
.pillar h3 { font-size: 19px; font-weight: 650; letter-spacing: -0.015em; margin: 0 0 9px; }
|
||||
.pillar p { font-size: 14.5px; color: var(--text-muted); line-height: 1.6; margin: 0; }
|
||||
.pillar.span2 { grid-column: span 1; }
|
||||
|
||||
/* ── How it works ────────────────────────────────────────────── */
|
||||
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 48px; }
|
||||
.step { padding: 30px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); position: relative; }
|
||||
.step .sn { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--honey); letter-spacing: .1em; }
|
||||
.step h3 { font-size: 21px; font-weight: 600; letter-spacing: -0.02em; margin: 16px 0 10px; }
|
||||
.step p { font-size: 14.5px; color: var(--text-muted); line-height: 1.6; margin: 0; }
|
||||
.step .line { position: absolute; top: 42px; right: -10px; color: var(--line-strong); font-size: 20px; }
|
||||
|
||||
/* ── Self-evolve ───────────────────────────── */
|
||||
.evolve-grid { margin-top: 44px; display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
|
||||
.ladder-viz { display: grid; gap: 10px; }
|
||||
.lrow { display: grid; grid-template-columns: 40px 1fr 52px; gap: 14px; align-items: center; }
|
||||
.lrow .lv { font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--text-dim); }
|
||||
.lrow.top .lv { color: var(--honey); }
|
||||
.lrow .lt { height: 30px; border-radius: 8px; background: var(--surface); border: 1px solid var(--line-soft); overflow: hidden; }
|
||||
.lrow .lf { height: 100%; border-radius: 7px 0 0 7px; background: var(--surface-3); }
|
||||
.lrow.top .lf { background: linear-gradient(90deg, var(--honey-deep), var(--honey-bright)); }
|
||||
.lrow .ls { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--text-2); } .lrow.top .ls { color: var(--honey); }
|
||||
.evolve-cards { display: grid; gap: 14px; }
|
||||
.ecard { padding: 20px 22px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); }
|
||||
.ecard h3 { font-size: 17px; font-weight: 650; letter-spacing: -0.015em; margin: 0 0 7px; display:flex; align-items:center; gap:10px; }
|
||||
.ecard h3 .en { font-family: var(--mono); font-size: 12px; color: var(--honey); }
|
||||
.ecard p { margin: 0; font-size: 14.5px; color: var(--text-muted); line-height: 1.55; }
|
||||
|
||||
/* ── Proof ───────────────────────────────────────────────────── */
|
||||
.proof { background: var(--bg-2); border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
|
||||
.proof-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 46px; }
|
||||
.stat-card { padding: 30px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); }
|
||||
.stat-card .cap { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.stat-card .stat { font-size: 48px; font-weight: 750; letter-spacing: -0.04em; line-height: 1; margin: 14px 0 6px; color: var(--honey); }
|
||||
.stat-card .nm { font-size: 16px; font-weight: 650; letter-spacing: -0.01em; margin-bottom: 8px; }
|
||||
.stat-card p { font-size: 13.5px; color: var(--text-muted); line-height: 1.6; margin: 0; }
|
||||
.methodology { margin-top: 26px; padding: 18px 22px; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft); display: flex; gap: 14px; align-items: flex-start; }
|
||||
.methodology .mono { font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--healthy); padding: 5px 9px; border: 1px solid color-mix(in srgb, var(--healthy) 35%, transparent); border-radius: 7px; flex: none; }
|
||||
.methodology p { margin: 0; font-size: 13.5px; color: var(--text-muted); line-height: 1.6; }
|
||||
.methodology p b { color: var(--text-2); }
|
||||
/* comparison bars */
|
||||
.bench { margin-top: 44px; display: grid; gap: 12px; }
|
||||
.barrow { display: grid; grid-template-columns: 168px 1fr 58px; gap: 16px; align-items: center; }
|
||||
.barrow .blab { font-size: 13.5px; font-weight: 600; text-align: right; line-height: 1.15; }
|
||||
.barrow .blab small { display: block; font-weight: 400; color: var(--text-dim); font-size: 10.5px; font-family: var(--mono); margin-top: 2px; }
|
||||
.barrow .track { height: 32px; border-radius: 9px; background: var(--surface); border: 1px solid var(--line-soft); overflow: hidden; }
|
||||
.barrow .fill { height: 100%; border-radius: 8px 0 0 8px; background: var(--surface-3); }
|
||||
.barrow.us .fill { background: linear-gradient(90deg, var(--honey-deep), var(--honey-bright)); box-shadow: var(--honey-glow); }
|
||||
.barrow .bval { font-family: var(--mono); font-size: 14px; font-weight: 600; color: var(--text-2); }
|
||||
.barrow.us .blab { color: var(--text); }
|
||||
.barrow.us .bval { color: var(--honey); }
|
||||
.bench-note { margin-top: 14px; font-size: 12.5px; color: var(--text-dim); font-family: var(--mono); display: flex; align-items: center; gap: 8px; }
|
||||
.bench-note b { color: var(--healthy); }
|
||||
/* bring-your-own-agent / shared memory band */
|
||||
.byo { background: var(--bg-2); border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
|
||||
.byo-flow { margin-top: 44px; display: flex; align-items: center; justify-content: center; gap: 0; flex-wrap: wrap; }
|
||||
.byo-node { padding: 16px 16px; border-radius: var(--r-lg); border: 1px solid var(--line-strong); background: var(--surface); min-width: 140px; max-width: 178px; }
|
||||
.byo-node .t { font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px; }
|
||||
.byo-node b { font-size: 15px; font-weight: 650; }
|
||||
.byo-node small { display: block; font-size: 12px; color: var(--text-muted); margin-top: 4px; line-height: 1.4; }
|
||||
.byo-node.hive { border-color: var(--honey-line); box-shadow: var(--honey-glow); background: linear-gradient(150deg,var(--surface-2),var(--surface)); }
|
||||
.byo-arrow { color: var(--honey); font-size: 20px; padding: 0 12px; }
|
||||
.byo-arrow small { display:block; font-family: var(--mono); font-size: 9px; color: var(--text-dim); text-transform:uppercase; letter-spacing:.1em; text-align:center; }
|
||||
.byo-cards { margin-top: 30px; display: grid; grid-template-columns: repeat(3,1fr); gap: 16px; }
|
||||
@media (max-width: 760px){ .byo-cards { grid-template-columns: 1fr; } }
|
||||
|
||||
/* ── Personas ────────────────────────────────────────────────── */
|
||||
.persona-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; margin-top: 44px; }
|
||||
.ptile { padding: 16px; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft); display: flex; align-items: center; gap: 12px; transition: .16s; cursor: default; }
|
||||
.ptile:hover { border-color: var(--honey-line); background: var(--surface-2); transform: translateY(-2px); }
|
||||
.ptile .ph { width: 30px; height: 34px; flex: none; background: var(--surface-3); display: grid; place-items: center; font-size: 13px; font-weight: 800; color: var(--honey); }
|
||||
.ptile b { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; }
|
||||
|
||||
/* ── Pricing ─────────────────────────────────────────────────── */
|
||||
.price-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 48px; align-items: stretch; }
|
||||
.plan { padding: 30px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); display: flex; flex-direction: column; }
|
||||
.plan.feat { border-color: var(--honey-line); box-shadow: var(--honey-glow); position: relative; }
|
||||
.plan .pop { position: absolute; top: -11px; left: 30px; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #1a1407; background: var(--honey); padding: 4px 11px; border-radius: 999px; }
|
||||
.plan .pname { font-size: 15px; font-weight: 600; color: var(--text-2); }
|
||||
.plan .pprice { font-size: 38px; font-weight: 750; letter-spacing: -0.03em; margin: 12px 0 2px; }
|
||||
.plan .pprice small { font-size: 15px; font-weight: 500; color: var(--text-muted); letter-spacing: 0; }
|
||||
.plan .ptag { font-size: 13.5px; color: var(--text-muted); margin-bottom: 22px; min-height: 38px; }
|
||||
.plan ul { list-style: none; margin: 0 0 26px; padding: 0; display: grid; gap: 11px; flex: 1; }
|
||||
.plan li { font-size: 13.5px; color: var(--text-2); display: grid; grid-template-columns: 18px 1fr; gap: 9px; line-height: 1.4; }
|
||||
.plan li svg { width: 15px; height: 15px; stroke: var(--healthy); fill: none; stroke-width: 2.2; margin-top: 2px; }
|
||||
.kvark-row { margin-top: 18px; padding: 22px 26px; border-radius: var(--r-lg); background: var(--bg-2); border: 1px dashed var(--line-strong); display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
|
||||
.kvark-row .kx { flex: 1; min-width: 260px; }
|
||||
.kvark-row b { font-size: 15px; font-weight: 650; }
|
||||
.kvark-row p { margin: 4px 0 0; font-size: 13.5px; color: var(--text-muted); }
|
||||
.kvark-row a { font-size: 14px; font-weight: 650; color: var(--honey); text-decoration: none; white-space: nowrap; }
|
||||
.kvark-row a:hover { color: var(--honey-bright); }
|
||||
|
||||
/* ── Final CTA ───────────────────────────────────────────────── */
|
||||
.final { text-align: center; padding: 110px 0; position: relative; overflow: hidden; }
|
||||
.final .comb { position: absolute; inset: 0; opacity: .6; pointer-events: none; mask-image: radial-gradient(80% 80% at 50% 50%, black, transparent 70%); }
|
||||
.final h2 { font-size: clamp(32px, 4.6vw, 56px); font-weight: 600; letter-spacing: -0.03em; margin: 0 0 18px; position: relative; }
|
||||
.final h2 em { font-style: normal; color: var(--honey); }
|
||||
.final p { font-size: 18px; color: var(--text-2); max-width: 52ch; margin: 0 auto 30px; line-height: 1.55; position: relative; }
|
||||
.final .cta-row { display: inline-flex; gap: 13px; flex-wrap: wrap; justify-content: center; position: relative; }
|
||||
|
||||
/* ── Footer ──────────────────────────────────────────────────── */
|
||||
footer { border-top: 1px solid var(--line-soft); padding: 56px 0 40px; }
|
||||
.foot-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 32px; }
|
||||
.foot-brand b { font-size: 18px; font-weight: 700; }
|
||||
.foot-brand p { font-size: 13.5px; color: var(--text-muted); margin: 12px 0 0; max-width: 30ch; line-height: 1.55; }
|
||||
.foot-col h4 { font-size: 12px; font-family: var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); margin: 0 0 14px; }
|
||||
.foot-col a { display: block; font-size: 13.5px; color: var(--text-muted); text-decoration: none; padding: 4px 0; }
|
||||
.foot-col a:hover { color: var(--honey); }
|
||||
.foot-base { margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--line-soft); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); }
|
||||
|
||||
@media (max-width: 940px) {
|
||||
.nav .links { display: none; }
|
||||
.hero-grid { grid-template-columns: 1fr; gap: 52px; }
|
||||
.hive { max-width: 380px; }
|
||||
.pillars-grid, .steps, .proof-grid, .price-grid { grid-template-columns: 1fr; }
|
||||
.evolve-grid, .byo-cards { grid-template-columns: 1fr; }
|
||||
.foot-grid { grid-template-columns: 1fr 1fr; }
|
||||
.step .line { display: none; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ═══════════════════ NAV ═══════════════════ -->
|
||||
<nav class="nav" id="nav">
|
||||
<div class="brand"><div class="mark hex">W</div><b>Waggle</b></div>
|
||||
<div class="links">
|
||||
<a href="#how">How it works</a>
|
||||
<a href="#pillars">Why Waggle</a>
|
||||
<a href="#agents">Your agents</a>
|
||||
<a href="#proof">Proof</a>
|
||||
<a href="#evolve">Self-evolving</a>
|
||||
<a href="#personas">Personas</a>
|
||||
<a href="#pricing">Pricing</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button class="themebtn" id="themebtn" title="Toggle light / dark" aria-label="Toggle theme">☾</button>
|
||||
<a href="#" class="signin">Sign in</a>
|
||||
<a href="#pricing" class="btn btn-primary">Start free</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- ═══════════════════ HERO ═══════════════════ -->
|
||||
<header class="hero">
|
||||
<div class="comb"></div>
|
||||
<div class="container hero-grid">
|
||||
<div class="reveal">
|
||||
<span class="eyebrow"><span class="dot"></span>The AI workspace for experts — not AI experts</span>
|
||||
<h1 class="hero-h">Your AI doesn't reset.<br><em>Your work doesn't either.</em></h1>
|
||||
<p class="sub">One local knowledge graph feeding Claude, GPT, Gemini — or a small model on your own machine. Stop pasting context into a blank box. It lives once, persists across every model, and compounds with every session you finish.</p>
|
||||
<div class="cta-row">
|
||||
<a href="#pricing" class="btn btn-primary btn-lg">Start free — local-first →</a>
|
||||
<a href="#how" class="btn btn-ghost btn-lg">See how it works</a>
|
||||
</div>
|
||||
<div class="chips">
|
||||
<a href="#proof" class="chip" style="color:var(--honey);border-color:var(--honey-line);background:var(--honey-wash);text-decoration:none;font-weight:600"><span class="dot" style="background:var(--honey)"></span>New — #1 on LoCoMo, and it's local</a>
|
||||
<span class="chip"><span class="dot"></span>Local-first by default</span>
|
||||
<span class="chip"><span class="dot"></span>Any model, even small ones</span>
|
||||
<span class="chip"><span class="dot"></span>Your data never leaves</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reveal">
|
||||
<div class="hive" id="hive">
|
||||
<svg class="wires" viewBox="0 0 460 460" aria-hidden="true">
|
||||
<line class="wire" x1="230" y1="230" x2="230" y2="60"></line>
|
||||
<line class="wire" x1="230" y1="230" x2="396" y2="230"></line>
|
||||
<line class="wire" x1="230" y1="230" x2="230" y2="400"></line>
|
||||
<line class="wire" x1="230" y1="230" x2="64" y2="230"></line>
|
||||
<line class="flow" x1="230" y1="60" x2="230" y2="230"></line>
|
||||
<line class="flow" x1="396" y1="230" x2="230" y2="230" style="animation-delay:.9s"></line>
|
||||
<line class="flow" x1="230" y1="230" x2="230" y2="400" style="animation-delay:1.7s"></line>
|
||||
<line class="flow" x1="64" y1="230" x2="230" y2="230" style="animation-delay:2.5s"></line>
|
||||
</svg>
|
||||
|
||||
<div class="hexcell core" style="left:50%;top:50%">
|
||||
<div class="hx hex">
|
||||
<div class="label">Your hive</div>
|
||||
<div class="big">One mind,<br>every model</div>
|
||||
<div class="meta">~/.waggle · local</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hexcell sat" style="left:50%;top:13%"><div class="hx hex"><div class="prov">Claude</div><div class="act recall">recall</div></div></div>
|
||||
<div class="hexcell sat" style="left:86%;top:50%"><div class="hx hex"><div class="prov">GPT-5</div><div class="act recall">recall</div></div></div>
|
||||
<div class="hexcell sat" style="left:50%;top:87%"><div class="hx hex"><div class="prov">Qwen · local</div><div class="act commit">commit</div></div></div>
|
||||
<div class="hexcell sat" style="left:14%;top:50%"><div class="hx hex"><div class="prov">Gemini</div><div class="act recall">recall</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ═══════════════════ TRUST BAND ═══════════════════ -->
|
||||
<div class="trust">
|
||||
<div class="container row">
|
||||
<div class="badge"><span class="mk hex"></span>Backed by Egzakta Group — building for regulated industries since 2010</div>
|
||||
<div class="signals">
|
||||
<span><span class="dot"></span>Local-first</span>
|
||||
<span><span class="dot"></span>Model-agnostic</span>
|
||||
<span><span class="dot"></span>Apache-2.0 substrate</span>
|
||||
<span><span class="dot"></span>EU AI Act audit-ready</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════ PROBLEM ═══════════════════ -->
|
||||
<section class="band problem">
|
||||
<div class="container reveal">
|
||||
<div class="sec-eyebrow">AI for doing your work — not operating it</div>
|
||||
<h2 class="sec-h">All the power built for engineers. <em>None of the homework.</em></h2>
|
||||
<p class="sec-sub">The most capable AI tools were built for people who want to <i>operate</i> AI — endless settings, prompts, and plumbing to master before you produce anything. Waggle takes the opposite bet: your time is too valuable to spend on AI plumbing, so we run it underneath and hand back finished work. You didn't become an expert to babysit a model.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ PILLARS ═══════════════════ -->
|
||||
<section class="band" id="pillars">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">Why Waggle</div>
|
||||
<h2 class="sec-h">Two memories working together — so you never start from a <em>stranger.</em></h2>
|
||||
</div>
|
||||
<div class="pillars-grid">
|
||||
<div class="pillar reveal">
|
||||
<div class="pn"><div class="ic"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M5.5 21a7 7 0 0 1 13 0"/></svg></div><span class="num">01</span></div>
|
||||
<h3>It knows you</h3>
|
||||
<p>You're known here — never re-introduce yourself, never start from a stranger. It already knows how you think and how you like your work done.</p>
|
||||
</div>
|
||||
<div class="pillar reveal">
|
||||
<div class="pn"><div class="ic"><svg viewBox="0 0 24 24"><path d="M4 6c0-1 1-2 3-2s3 1 3 2v14c0-1-1-2-3-2s-3 1-3 2zM20 6c0-1-1-2-3-2s-3 1-3 2v14c0-1 1-2 3-2s3 1 3 2z"/></svg></div><span class="num">02</span></div>
|
||||
<h3>It knows your work</h3>
|
||||
<p>Nothing is lost. Walk back into any project after a day, a week, a quarter — it's all still there, exactly as you left it.</p>
|
||||
</div>
|
||||
<div class="pillar reveal">
|
||||
<div class="pn"><div class="ic"><svg viewBox="0 0 24 24"><path d="M12 3v3M12 18v3M5 12H2M22 12h-3M6 6l-2-2M20 20l-2-2M6 18l-2 2M20 4l-2 2"/><circle cx="12" cy="12" r="3.5"/></svg></div><span class="num">03</span></div>
|
||||
<h3>It runs the AI</h3>
|
||||
<p>You stay the expert. The prompting, routing, and scaffolding run underneath — on tap when you want them, out of your way when you don't.</p>
|
||||
</div>
|
||||
<div class="pillar reveal">
|
||||
<div class="pn"><div class="ic"><svg viewBox="0 0 24 24"><path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/></svg></div><span class="num">04</span></div>
|
||||
<h3>Your best work — and it's yours</h3>
|
||||
<p>Spreadsheets to the last detail, decks that hold up in the room, docs polished to the final word. Everything you ship is genuinely your best, and unmistakably yours.</p>
|
||||
</div>
|
||||
<div class="pillar reveal">
|
||||
<div class="pn"><div class="ic"><svg viewBox="0 0 24 24"><path d="M12 3 4 6v6c0 5 3.5 7.5 8 9 4.5-1.5 8-4 8-9V6z"/></svg></div><span class="num">05</span></div>
|
||||
<h3>It stays yours</h3>
|
||||
<p>Local-first and model-agnostic — runs on any model, even a small one on your own machine. Yours to keep, export, or delete, anytime.</p>
|
||||
</div>
|
||||
<div class="pillar reveal" style="background:linear-gradient(150deg,var(--surface-2),var(--surface));border-color:var(--honey-line)">
|
||||
<div class="pn"><div class="ic" style="background:var(--honey);border-color:var(--honey)"><svg viewBox="0 0 24 24" style="stroke:#1a1407"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><span class="num">↳</span></div>
|
||||
<h3>The full controls, one click away</h3>
|
||||
<p>Want the prompts, the routing, the raw model picker back? They've never gone anywhere — Waggle just stops making you use them.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ HOW IT WORKS ═══════════════════ -->
|
||||
<section class="band" id="how" style="background:var(--bg-2);border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)">
|
||||
<div class="container">
|
||||
<div class="sec-head reveal">
|
||||
<div class="sec-eyebrow">How it works</div>
|
||||
<h2 class="sec-h">A simple division of <em>labor.</em></h2>
|
||||
<p class="sec-sub">You bring the judgment. Waggle brings the AI. Open it once and your context and your work-in-progress are already there — nothing re-explained, nothing lost.</p>
|
||||
</div>
|
||||
<div class="steps">
|
||||
<div class="step reveal">
|
||||
<div class="sn">STEP 01</div><span class="line">→</span>
|
||||
<h3>Bring it all in</h3>
|
||||
<p>Start fresh and it learns you fast — or import your history. One-click import from ChatGPT, Claude, and Cursor: brought in on your machine, stays on your machine.</p>
|
||||
</div>
|
||||
<div class="step reveal">
|
||||
<div class="sn">STEP 02</div><span class="line">→</span>
|
||||
<h3>Open to what's waiting</h3>
|
||||
<p>Open it and you're already moving: here's where you left off, here's what ran overnight, here's what's next. Your work picks up mid-stride, never from a blank box.</p>
|
||||
</div>
|
||||
<div class="step reveal">
|
||||
<div class="sn">STEP 03</div>
|
||||
<h3>Do the work that's yours</h3>
|
||||
<p>You make the calls; Waggle runs the AI underneath and hands you finished work. Close it, and all of it stays right where you left it for next time.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ BRING YOUR OWN AGENT ═══════════════════ -->
|
||||
<section class="band byo" id="agents">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">Works with the tools you already use</div>
|
||||
<h2 class="sec-h">Bring your own agent. <em>It inherits the memory.</em></h2>
|
||||
<p class="sec-sub">Launch Claude Code, Cursor, or Codex straight from a Waggle workspace and it opens already knowing the work — then commits what it does back to the hive. No copy-paste, no re-explaining. Nothing leaves your machine.</p>
|
||||
</div>
|
||||
|
||||
<div class="byo-flow reveal">
|
||||
<div class="byo-node"><div class="t">You launch</div><b>Claude Code</b><small>opened with this workspace wired in</small></div>
|
||||
<div class="byo-arrow">⇄<small>hooks</small></div>
|
||||
<div class="byo-node"><div class="t">It works</div><b>recall + commit</b><small>reads context, writes results back</small></div>
|
||||
<div class="byo-arrow">⇄<small>local</small></div>
|
||||
<div class="byo-node hive"><div class="t">Your workspace</div><b>The hive</b><small>one local memory, shared</small></div>
|
||||
</div>
|
||||
|
||||
<div class="byo-cards">
|
||||
<div class="pillar reveal" style="margin:0"><div class="pn"><span class="num">↓</span></div><h3>Opens knowing the work</h3><p>The agent recalls this workspace's decisions, constraints and history the moment it starts — no prompt-stuffing.</p></div>
|
||||
<div class="pillar reveal" style="margin:0"><div class="pn"><span class="num">↑</span></div><h3>Writes back, attributed</h3><p>Everything it does flows into the hive with provenance, so Waggle and your next session pick up where it left off.</p></div>
|
||||
<div class="pillar reveal" style="margin:0"><div class="pn"><span class="num">⬡</span></div><h3>Reversible & local</h3><p>Hooks install and uninstall cleanly. The memory stays on your machine; you can verify or remove anytime.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ PROOF ═══════════════════ -->
|
||||
<section class="band proof" id="proof">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">State of the art · June 2026</div>
|
||||
<h2 class="sec-h">The best long-term memory on record. <em>And it runs on your machine.</em></h2>
|
||||
<p class="sec-sub">On <b style="color:var(--text)">LoCoMo</b> — the field's standard test for long-term conversational memory — Waggle's open-source substrate scores <b style="color:var(--text)">87.66%</b>, a new state of the art. Measured under the prior leader's own protocol and judge, whose pipeline we reproduced to within 0.03 points before comparing.</p>
|
||||
</div>
|
||||
|
||||
<div class="bench reveal">
|
||||
<div class="barrow us">
|
||||
<div class="blab">Waggle · Hive Mind<small>ours · local</small></div>
|
||||
<div class="track"><div class="fill" style="width:87.7%"></div></div>
|
||||
<div class="bval">87.66</div>
|
||||
</div>
|
||||
<div class="barrow">
|
||||
<div class="blab">Memori<small>prev. SOTA</small></div>
|
||||
<div class="track"><div class="fill" style="width:81.95%"></div></div>
|
||||
<div class="bval">81.95</div>
|
||||
</div>
|
||||
<div class="barrow">
|
||||
<div class="blab">LangMem<small>corrected</small></div>
|
||||
<div class="track"><div class="fill" style="width:78.05%"></div></div>
|
||||
<div class="bval">78.05</div>
|
||||
</div>
|
||||
<div class="barrow">
|
||||
<div class="blab">Mem0<small>baseline</small></div>
|
||||
<div class="track"><div class="fill" style="width:62.47%"></div></div>
|
||||
<div class="bval">62.47</div>
|
||||
</div>
|
||||
<div class="bench-note">⊡ <b>+5.71 points</b> over the prior best published memory system · z = 4.42, p < 10⁻⁵ · leads every question category</div>
|
||||
</div>
|
||||
|
||||
<div class="proof-grid">
|
||||
<div class="stat-card reveal">
|
||||
<div class="cap">Single-hop recall</div>
|
||||
<div class="stat">92.75%</div>
|
||||
<div class="nm">Within a point of perfect recall</div>
|
||||
<p>That's ~1 point off the <b>full-context ceiling</b> — what a model scores with the <i>entire</i> conversation pasted in. The memory recalls almost as well as having everything in front of it.</p>
|
||||
</div>
|
||||
<div class="stat-card reveal">
|
||||
<div class="cap">Deployment</div>
|
||||
<div class="stat">100%</div>
|
||||
<div class="nm">Local — nothing leaves the machine</div>
|
||||
<p>Every memory operation runs on-device — SQLite, local embeddings, an in-process reranker. Warm recalls in <b>58–83 ms</b>. The strongest LoCoMo result on record for a fully local system.</p>
|
||||
</div>
|
||||
<div class="stat-card reveal">
|
||||
<div class="cap">Open source · Apache-2.0</div>
|
||||
<div class="stat">Run it</div>
|
||||
<div class="nm">Audit the layer yourself</div>
|
||||
<p>The substrate and the benchmark harness are public. Fork it, read the graph, reproduce the score offline. No black box — <span class="mono" style="font-family:var(--mono);font-size:12px;color:var(--text-2)">github.com/marolinik/hive-mind</span>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="methodology reveal">
|
||||
<span class="mono">Method</span>
|
||||
<p><b>LoCoMo</b>, N = 1,540 questions, GPT-4.1-mini as answerer and judge — the prior SOTA's exact published protocol, reproduced in-harness to 0.03 points before comparison. The intelligence lives in the memory layer, not the model, so it travels with you — even onto a small model on your own machine. <b>Honest caveat:</b> we spend more tokens per question than the leanest systems; accuracy first, efficiency work is underway.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ SELF-EVOLVING ═══════════════════ -->
|
||||
<section class="band" id="evolve">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">The compounding moat</div>
|
||||
<h2 class="sec-h">It doesn't just remember. <em>It gets better.</em></h2>
|
||||
<p class="sec-sub">Your skills aren't static prompts. Waggle re-optimizes them against real outcomes, keeps every version with the score that earned it — and the good ones spread across your agents and workspaces. The longer you use it, the better it works.</p>
|
||||
</div>
|
||||
<div class="evolve-grid">
|
||||
<div class="ladder-viz reveal">
|
||||
<div class="lrow"><span class="lv">v1</span><div class="lt"><div class="lf" style="width:71%"></div></div><span class="ls">71%</span></div>
|
||||
<div class="lrow"><span class="lv">v2</span><div class="lt"><div class="lf" style="width:84%"></div></div><span class="ls">84%</span></div>
|
||||
<div class="lrow top"><span class="lv">v3</span><div class="lt"><div class="lf" style="width:91%"></div></div><span class="ls">91%</span></div>
|
||||
</div>
|
||||
<div class="evolve-cards">
|
||||
<div class="ecard reveal"><h3><span class="en">01</span>Skills that self-improve</h3><p>Each skill is re-tuned against held-out tasks and judged by an ensemble of models. A new version only ships if it actually wins — and the old one stays, so you can always roll back.</p></div>
|
||||
<div class="ecard reveal"><h3><span class="en">02</span>Knowledge that spreads</h3><p>When one agent learns something good, the others don't start from zero. Skills and tool setups diffuse across your agents and workspaces — the waggle dance. On a team, the whole org levels up at once.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ PERSONAS ═══════════════════ -->
|
||||
<section class="band" id="personas">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">Built for</div>
|
||||
<h2 class="sec-h">Thirteen ways people work. <em>One memory layer.</em></h2>
|
||||
<p class="sec-sub">Hunters chase, builders ship, orchestrators coordinate. Waggle remembers — across roles, across tools, across the moments in between.</p>
|
||||
</div>
|
||||
<div class="persona-grid" id="personaGrid"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ PRICING ═══════════════════ -->
|
||||
<section class="band" id="pricing" style="background:var(--bg-2);border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)">
|
||||
<div class="container">
|
||||
<div class="sec-head wide reveal">
|
||||
<div class="sec-eyebrow">Pricing</div>
|
||||
<h2 class="sec-h">Free for individuals. <em>Honest pricing</em> for everyone else.</h2>
|
||||
<p class="sec-sub">Three tiers, no feature-count games. You pay for the scale of the team using the memory — not for arbitrary check-marks. Memory is free forever.</p>
|
||||
</div>
|
||||
<div class="price-grid">
|
||||
<div class="plan reveal">
|
||||
<div class="pname">Solo</div>
|
||||
<div class="pprice">$0<small> / forever</small></div>
|
||||
<div class="ptag">For individuals exploring an AI workspace.</div>
|
||||
<ul>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Personal memory graph</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>All major LLMs supported</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Local-first by default</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>EU AI Act audit reports</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Apache-2.0 substrate</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn-ghost">Download free</a>
|
||||
</div>
|
||||
<div class="plan feat reveal">
|
||||
<span class="pop">Most popular</span>
|
||||
<div class="pname">Pro</div>
|
||||
<div class="pprice">$19<small> / month</small></div>
|
||||
<div class="ptag">For power users compounding across projects.</div>
|
||||
<ul>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Everything in Solo</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Priority sync across devices</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Advanced graph queries</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Marketplace skills & connectors</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Personal API key vault</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn-primary">Start 14-day trial</a>
|
||||
</div>
|
||||
<div class="plan reveal">
|
||||
<div class="pname">Teams</div>
|
||||
<div class="pprice">$49<small> / seat / mo</small></div>
|
||||
<div class="ptag">Shared memory without losing privacy. 3-seat minimum.</div>
|
||||
<ul>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Everything in Pro</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Shared team memory graph</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>WaggleDance multi-agent</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>SSO & role-based access</li>
|
||||
<li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>SOC 2 Type II on request</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn-ghost">Start team trial →</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kvark-row reveal">
|
||||
<div class="kx">
|
||||
<b>Need it on your organization's sovereign infrastructure?</b>
|
||||
<p>Everything Waggle does — on your infrastructure, your permissions, full audit trail. Your data never leaves your perimeter. That's KVARK, by Egzakta Group.</p>
|
||||
</div>
|
||||
<a href="#">Talk to the KVARK team →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ FINAL CTA ═══════════════════ -->
|
||||
<section class="final">
|
||||
<div class="comb"></div>
|
||||
<div class="container">
|
||||
<h2 class="reveal">Be the expert. <em>We'll be the AI.</em></h2>
|
||||
<p class="reveal">Bring your work home to the one place that knows you, knows your projects, and makes everything you ship genuinely your best — then pick up exactly where you left off.</p>
|
||||
<div class="cta-row reveal">
|
||||
<a href="#pricing" class="btn btn-primary btn-lg">Start free — local-first →</a>
|
||||
<a href="#how" class="btn btn-ghost btn-lg">See how it works</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════ FOOTER ═══════════════════ -->
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="foot-grid">
|
||||
<div class="foot-brand">
|
||||
<div class="brand"><div class="mark hex">W</div><b>Waggle</b></div>
|
||||
<p>The AI workspace where memory persists. Local-first, model-agnostic, audit-ready. A product of Egzakta Group.</p>
|
||||
</div>
|
||||
<div class="foot-col"><h4>Product</h4><a href="#">Download</a><a href="#pricing">Pricing</a><a href="#personas">Personas</a><a href="#how">How it works</a></div>
|
||||
<div class="foot-col"><h4>Research</h4><a href="#proof">Methodology</a><a href="#">Benchmarks</a><a href="#">Changelog</a><a href="#">Open source</a></div>
|
||||
<div class="foot-col"><h4>Company</h4><a href="#">About Egzakta</a><a href="#">EU AI Act</a><a href="#">Privacy</a><a href="#">Contact</a></div>
|
||||
</div>
|
||||
<div class="foot-base">
|
||||
<span>© 2026 Egzakta Group · Waggle</span>
|
||||
<span>v1.0 · waggle-os.ai · built calmly across DACH · CEE · UK</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
/* ── theme ──────────────────────────────────────────────────────── */
|
||||
const root = document.documentElement, tb = document.getElementById('themebtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tb.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tb.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
|
||||
/* ── nav shadow ─────────────────────────────────────────────────── */
|
||||
const nav = document.getElementById('nav');
|
||||
addEventListener('scroll', () => nav.classList.toggle('scrolled', scrollY > 12), { passive: true });
|
||||
|
||||
/* ── personas ───────────────────────────────────────────────────── */
|
||||
const personas = ['Researcher','Writer','Analyst','Engineer','Project manager','Executive assistant','Sales','Marketer','Product manager','HR','Legal','Finance','Consultant'];
|
||||
document.getElementById('personaGrid').innerHTML = personas.map(p =>
|
||||
`<div class="ptile"><span class="ph hex">${p[0]}</span><b>${p}</b></div>`).join('');
|
||||
|
||||
/* ── reveal on scroll (with above-the-fold + safety fallback) ────── */
|
||||
const io = new IntersectionObserver((es) => {
|
||||
es.forEach((e) => { if(e.isIntersecting){ e.target.classList.add('in'); io.unobserve(e.target); } });
|
||||
}, { rootMargin: '0px 0px -6% 0px' });
|
||||
const reveals = [...document.querySelectorAll('.reveal')];
|
||||
reveals.forEach(el => io.observe(el));
|
||||
// Above-the-fold: reveal anything already on screen at load (don't wait for a scroll).
|
||||
requestAnimationFrame(() => {
|
||||
reveals.forEach(el => { if (el.getBoundingClientRect().top < innerHeight * 0.94) el.classList.add('in'); });
|
||||
});
|
||||
// Safety net: never leave content invisible.
|
||||
setTimeout(() => reveals.forEach(el => el.classList.add('in')), 1600);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,905 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle, reimagined — a concept exploration</title>
|
||||
<link rel="stylesheet" href="styles/waggle.css">
|
||||
<style>
|
||||
html { scroll-behavior: smooth; }
|
||||
body { overflow-x: hidden; }
|
||||
|
||||
/* ── Top chrome ──────────────────────────────────────────────── */
|
||||
.topbar {
|
||||
position: fixed; inset: 0 0 auto 0; z-index: 50;
|
||||
height: 60px; display: flex; align-items: center; gap: 20px;
|
||||
padding: 0 28px;
|
||||
background: color-mix(in srgb, var(--bg) 78%, transparent);
|
||||
backdrop-filter: blur(18px) saturate(1.4);
|
||||
-webkit-backdrop-filter: blur(18px) saturate(1.4);
|
||||
border-bottom: 1px solid var(--line-soft);
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 11px; }
|
||||
.brand .mark {
|
||||
width: 30px; height: 33px; display: grid; place-items: center;
|
||||
background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep));
|
||||
color: #1a1407; font-weight: 800; font-size: 15px;
|
||||
box-shadow: var(--honey-glow);
|
||||
}
|
||||
.brand b { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
|
||||
.brand .tag {
|
||||
font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.08em;
|
||||
text-transform: uppercase; color: var(--text-dim);
|
||||
padding-left: 12px; margin-left: 2px; border-left: 1px solid var(--line);
|
||||
}
|
||||
.topnav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
|
||||
.topnav a {
|
||||
font-size: 13px; color: var(--text-muted); text-decoration: none;
|
||||
padding: 7px 12px; border-radius: 8px; transition: .15s; font-weight: 500;
|
||||
}
|
||||
.topnav a:hover { color: var(--text); background: var(--surface-2); }
|
||||
.topnav { overflow-x: auto; max-width: 58vw; flex-wrap: nowrap; scrollbar-width: none; }
|
||||
.topnav::-webkit-scrollbar { display: none; }
|
||||
.topnav a { white-space: nowrap; }
|
||||
.topnav a.on { color: var(--honey-bright); }
|
||||
[data-theme="light"] .topnav a.on { color: var(--honey-deep); }
|
||||
.themebtn {
|
||||
margin-left: 8px; width: 38px; height: 38px; border-radius: 10px;
|
||||
border: 1px solid var(--line); background: var(--surface); color: var(--text-2);
|
||||
cursor: pointer; display: grid; place-items: center; transition: .15s;
|
||||
}
|
||||
.themebtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
main { max-width: 1080px; margin: 0 auto; padding: 0 28px; }
|
||||
section { padding: 100px 0; border-top: 1px solid var(--line-soft); }
|
||||
section:first-of-type { border-top: 0; }
|
||||
|
||||
.eyebrow {
|
||||
font-family: var(--mono); font-size: 12px; letter-spacing: 0.16em;
|
||||
text-transform: uppercase; color: var(--honey); margin: 0 0 18px;
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
.eyebrow::before { content: ''; width: 22px; height: 1px; background: var(--honey-line); }
|
||||
|
||||
h2.big {
|
||||
font-family: var(--sans); font-weight: 600;
|
||||
font-size: clamp(36px, 5vw, 60px); line-height: 1.02;
|
||||
letter-spacing: -0.015em; margin: 0 0 22px; text-wrap: balance;
|
||||
}
|
||||
h2.big em { font-style: normal; color: var(--honey); }
|
||||
.lede {
|
||||
font-size: 20px; line-height: 1.5; color: var(--text-2);
|
||||
max-width: 60ch; margin: 0; font-weight: 400;
|
||||
}
|
||||
.lede b { color: var(--text); font-weight: 600; }
|
||||
|
||||
/* ── Hero ─────────────────────────────────────────────────────── */
|
||||
.hero { padding: 168px 0 120px; position: relative; }
|
||||
.hero::before {
|
||||
content: ''; position: absolute; top: -40px; right: -120px;
|
||||
width: 560px; height: 560px; pointer-events: none; opacity: .5;
|
||||
background: radial-gradient(circle at center, var(--honey-wash), transparent 62%);
|
||||
}
|
||||
.hero .comb-deco {
|
||||
position: absolute; inset: 0; opacity: .6; pointer-events: none;
|
||||
mask-image: linear-gradient(120deg, transparent 40%, black 110%);
|
||||
}
|
||||
.hero h1 {
|
||||
font-family: var(--sans); font-weight: 600;
|
||||
font-size: clamp(46px, 7.5vw, 94px); line-height: 0.92;
|
||||
letter-spacing: -0.025em; margin: 22px 0 26px; position: relative;
|
||||
}
|
||||
.hero h1 em { font-style: normal; color: var(--honey); }
|
||||
.hero p { font-size: 21px; color: var(--text-2); max-width: 56ch; line-height: 1.5; position: relative; }
|
||||
.hero .meta {
|
||||
margin-top: 44px; display: flex; flex-wrap: wrap; gap: 10px; position: relative;
|
||||
}
|
||||
|
||||
/* ── Findings (critique) ──────────────────────────────────────── */
|
||||
.findings { margin-top: 56px; display: grid; gap: 18px; }
|
||||
.finding {
|
||||
display: grid; grid-template-columns: 56px 1fr; gap: 22px;
|
||||
padding: 26px 28px; border-radius: var(--r-lg);
|
||||
background: var(--surface); border: 1px solid var(--line-soft);
|
||||
transition: .2s;
|
||||
}
|
||||
.finding:hover { border-color: var(--line-strong); transform: translateY(-2px); box-shadow: var(--shadow); }
|
||||
.finding .n {
|
||||
font-family: var(--serif); font-size: 40px; line-height: 1;
|
||||
color: var(--honey); opacity: .85;
|
||||
}
|
||||
.finding h3 { margin: 2px 0 8px; font-size: 19px; font-weight: 650; letter-spacing: -0.01em; }
|
||||
.finding p { margin: 0; color: var(--text-muted); font-size: 15px; line-height: 1.55; }
|
||||
.finding .obs {
|
||||
margin-top: 12px; font-family: var(--mono); font-size: 12px;
|
||||
color: var(--text-dim); display: flex; gap: 8px; align-items: baseline;
|
||||
}
|
||||
.finding .obs b { color: var(--risk); font-weight: 500; }
|
||||
|
||||
/* ── Principles ───────────────────────────────────────────────── */
|
||||
.principles { margin-top: 52px; display: grid; grid-template-columns: repeat(2,1fr); gap: 18px; }
|
||||
.principle {
|
||||
padding: 30px; border-radius: var(--r-lg); position: relative; overflow: hidden;
|
||||
background: var(--surface); border: 1px solid var(--line-soft);
|
||||
}
|
||||
.principle .idx { font-family: var(--mono); font-size: 12px; color: var(--honey); letter-spacing: .1em; }
|
||||
.principle h3 { font-family: var(--sans); font-weight: 600; font-size: 28px; margin: 14px 0 10px; letter-spacing: -0.01em; }
|
||||
.principle p { margin: 0; color: var(--text-muted); font-size: 15px; }
|
||||
.principle .hexmark {
|
||||
position: absolute; right: -26px; bottom: -26px; width: 110px; height: 122px;
|
||||
background: var(--surface-2); opacity: .6;
|
||||
}
|
||||
|
||||
/* ── Identity / styleguide ────────────────────────────────────── */
|
||||
.sg-grid { margin-top: 48px; display: grid; gap: 22px; }
|
||||
.panel {
|
||||
background: var(--surface); border: 1px solid var(--line-soft);
|
||||
border-radius: var(--r-lg); padding: 30px;
|
||||
}
|
||||
.panel > .label {
|
||||
font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
|
||||
text-transform: uppercase; color: var(--text-dim); margin: 0 0 20px;
|
||||
}
|
||||
.swatches { display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px; }
|
||||
.sw { border-radius: var(--r); overflow: hidden; border: 1px solid var(--line-soft); }
|
||||
.sw .chip { height: 64px; }
|
||||
.sw .meta { padding: 9px 10px; }
|
||||
.sw .meta b { display: block; font-size: 12.5px; font-weight: 600; }
|
||||
.sw .meta span { font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); }
|
||||
.sem-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
|
||||
|
||||
.type-spec { display: grid; gap: 22px; }
|
||||
.type-spec .row { display: grid; grid-template-columns: 96px 1fr; gap: 24px; align-items: baseline; padding-bottom: 22px; border-bottom: 1px solid var(--line-soft); }
|
||||
.type-spec .row:last-child { border-bottom: 0; padding-bottom: 0; }
|
||||
.type-spec .k { font-family: var(--mono); font-size: 11px; color: var(--text-dim); letter-spacing: .08em; text-transform: uppercase; }
|
||||
.type-spec .serif-demo { font-family: var(--sans); font-weight: 600; font-size: 44px; line-height: 1; letter-spacing: -0.02em; }
|
||||
.type-spec .serif-demo em { font-style: normal; color: var(--honey); }
|
||||
.type-spec .sans-demo { font-size: 24px; font-weight: 600; letter-spacing: -0.01em; }
|
||||
.type-spec .sans-demo small { display: block; font-size: 14px; font-weight: 400; color: var(--text-muted); margin-top: 6px; letter-spacing: 0; }
|
||||
.type-spec .mono-demo { font-family: var(--mono); font-size: 15px; color: var(--text-2); }
|
||||
|
||||
/* ── IA before/after ──────────────────────────────────────────── */
|
||||
.ia-toggle { margin-top: 40px; display: inline-flex; padding: 4px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--line-soft); gap: 4px; }
|
||||
.ia-toggle button {
|
||||
font-family: var(--sans); font-size: 13.5px; font-weight: 600; cursor: pointer;
|
||||
padding: 9px 18px; border-radius: 9px; border: 0; background: transparent; color: var(--text-muted); transition: .15s;
|
||||
}
|
||||
.ia-toggle button.on { background: var(--honey); color: #1a1407; }
|
||||
.ia-cols { margin-top: 26px; display: grid; grid-template-columns: 300px 1fr; gap: 22px; align-items: start; }
|
||||
.navmock {
|
||||
background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: var(--r-lg);
|
||||
padding: 16px 12px; min-height: 460px;
|
||||
}
|
||||
.navmock .zone { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); padding: 14px 12px 6px; }
|
||||
.navmock .item {
|
||||
display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 9px;
|
||||
font-size: 13.5px; color: var(--text-2); transition: .12s;
|
||||
}
|
||||
.navmock .item .ic { width: 16px; height: 16px; border-radius: 5px; background: var(--surface-3); flex: none; }
|
||||
.navmock .item.on { background: var(--honey-wash); color: var(--text); }
|
||||
.navmock .item.on .ic { background: var(--honey); }
|
||||
.navmock .item.muted { opacity: .5; }
|
||||
.navmock .more { margin-top: 8px; padding: 9px 12px; font-size: 12.5px; color: var(--text-dim); font-family: var(--mono); border-top: 1px dashed var(--line); }
|
||||
.ia-note { color: var(--text-muted); font-size: 15.5px; line-height: 1.6; }
|
||||
.ia-note h3 { font-family: var(--sans); font-weight: 600; font-size: 30px; margin: 0 0 14px; letter-spacing: -0.01em; color: var(--text); }
|
||||
.ia-note ul { margin: 18px 0 0; padding: 0; list-style: none; display: grid; gap: 12px; }
|
||||
.ia-note li { display: grid; grid-template-columns: 18px 1fr; gap: 12px; font-size: 15px; }
|
||||
.ia-note li .b { color: var(--honey); font-weight: 700; }
|
||||
.ia-note li b { color: var(--text); }
|
||||
|
||||
/* ── Screen sections ──────────────────────────────────────────── */
|
||||
.screen-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
|
||||
.screen-head .open {
|
||||
font-size: 13.5px; font-weight: 600; color: var(--text); text-decoration: none;
|
||||
padding: 11px 18px; border-radius: 10px; border: 1px solid var(--line-strong);
|
||||
background: var(--surface); display: inline-flex; align-items: center; gap: 9px; transition: .15s; white-space: nowrap;
|
||||
}
|
||||
.screen-head .open:hover { border-color: var(--honey-line); color: var(--honey); box-shadow: var(--shadow); }
|
||||
.vary { margin-top: 16px; display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.vary .pill b { color: var(--text); }
|
||||
.frame {
|
||||
margin-top: 30px; border-radius: var(--r-xl); overflow: hidden;
|
||||
border: 1px solid var(--line); background: var(--bg-2);
|
||||
box-shadow: var(--shadow-lg); position: relative;
|
||||
}
|
||||
.frame .bar {
|
||||
height: 38px; display: flex; align-items: center; gap: 7px; padding: 0 16px;
|
||||
border-bottom: 1px solid var(--line-soft); background: var(--surface);
|
||||
}
|
||||
.frame .bar i { width: 11px; height: 11px; border-radius: 999px; background: var(--line-strong); }
|
||||
.frame .bar .u { margin-left: 14px; font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
.frame iframe { width: 100%; height: 660px; border: 0; display: block; background: var(--bg); }
|
||||
|
||||
.placeholder {
|
||||
height: 480px; display: grid; place-items: center; text-align: center;
|
||||
background:
|
||||
repeating-linear-gradient(135deg, var(--surface) 0 14px, var(--bg-2) 14px 28px);
|
||||
}
|
||||
.placeholder .inner { background: color-mix(in srgb, var(--bg) 60%, transparent); padding: 28px 34px; border-radius: var(--r-lg); backdrop-filter: blur(4px); }
|
||||
.placeholder .mono { color: var(--honey); font-size: 13px; letter-spacing: .1em; text-transform: uppercase; }
|
||||
.placeholder p { margin: 10px 0 0; color: var(--text-muted); font-size: 15px; }
|
||||
|
||||
/* ── Close ────────────────────────────────────────────────────── */
|
||||
.close-cta { text-align: center; padding: 120px 0 140px; }
|
||||
/* ── Coverage map ─────────────────────────────────────────────── */
|
||||
.cov { margin-top: 44px; display: grid; gap: 26px; }
|
||||
.covzone h3 { font-family: var(--mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--honey); margin: 0 0 14px; display: flex; align-items: center; gap: 10px; }
|
||||
.covzone h3::after { content: ''; flex: 1; height: 1px; background: var(--line-soft); }
|
||||
.covgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
|
||||
.covitem { display: flex; align-items: center; gap: 11px; padding: 13px 15px; border-radius: var(--r); border: 1px solid var(--line-soft); background: var(--surface); text-decoration: none; color: var(--text-2); transition: .14s; }
|
||||
a.covitem:hover { border-color: var(--honey-line); transform: translateY(-2px); box-shadow: var(--shadow); }
|
||||
.covitem .cst { width: 9px; height: 9px; border-radius: 999px; flex: none; }
|
||||
.covitem .cst.done { background: var(--honey); } .covitem .cst.within { background: var(--work); } .covitem .cst.queued { background: var(--line-strong); }
|
||||
.covitem .cst.next { background: var(--attention); } .covitem .cst.beta { background: var(--intel); }
|
||||
.covitem .cn { flex: 1; font-size: 13.5px; font-weight: 550; min-width: 0; } .covitem .cn b { color: var(--text); font-weight: 600; }
|
||||
.covitem .croute { font-family: var(--mono); font-size: 10px; color: var(--text-dim); white-space: nowrap; }
|
||||
.covlegend { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 4px; font-size: 12.5px; color: var(--text-muted); }
|
||||
.covlegend span { display: inline-flex; align-items: center; gap: 8px; } .covlegend .cst { width: 9px; height: 9px; border-radius: 999px; }
|
||||
@media (max-width: 860px){ .covgrid { grid-template-columns: 1fr; } }
|
||||
.close-cta h2 { font-family: var(--sans); font-weight: 600; font-size: clamp(34px,5vw,56px); letter-spacing: -0.02em; margin: 0 0 18px; }
|
||||
.close-cta h2 em { font-style: normal; color: var(--honey); }
|
||||
.close-cta p { color: var(--text-muted); max-width: 52ch; margin: 0 auto; font-size: 17px; }
|
||||
footer { border-top: 1px solid var(--line-soft); padding: 30px 28px; text-align: center; color: var(--text-dim); font-family: var(--mono); font-size: 12px; }
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.topnav { display: none; }
|
||||
.principles, .ia-cols { grid-template-columns: 1fr; }
|
||||
.swatches { grid-template-columns: repeat(3,1fr); }
|
||||
.finding { grid-template-columns: 1fr; gap: 8px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="topbar">
|
||||
<div class="brand">
|
||||
<div class="mark hex">W</div>
|
||||
<b>Waggle</b>
|
||||
<span class="tag">Reimagined · concept</span>
|
||||
</div>
|
||||
<nav class="topnav" id="topnav">
|
||||
<a href="#read">The read</a>
|
||||
<a href="#principles">Principles</a>
|
||||
<a href="#identity">Identity</a>
|
||||
<a href="#navigation">Navigation</a>
|
||||
<a href="#ia">⌘K</a>
|
||||
<a href="#landing">Landing</a>
|
||||
<a href="#home">Home</a>
|
||||
<a href="#chat">Chat</a>
|
||||
<a href="#workspace">Workspace</a>
|
||||
<a href="#launcher">Launcher</a>
|
||||
<a href="#storage">Storage</a>
|
||||
<a href="#surfaces">⌘K surfaces</a>
|
||||
<a href="#workspaces">Workspaces</a>
|
||||
<a href="#onboarding">Onboarding</a>
|
||||
<a href="#settings">Settings</a>
|
||||
<a href="#marketplace">Marketplace</a>
|
||||
<a href="#evolution">Moat</a>
|
||||
<a href="#auth">Auth</a>
|
||||
<a href="#billing">Billing</a>
|
||||
<a href="#habit">Habit</a>
|
||||
<a href="#appsurfaces">Surfaces</a>
|
||||
<a href="#benchmark">Bench</a>
|
||||
<a href="#platform">Platform</a>
|
||||
<a href="#coverage">Map</a>
|
||||
</nav>
|
||||
<button class="themebtn" id="themebtn" title="Toggle light / dark" aria-label="Toggle theme">☾</button>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- ───────────────────────── HERO ───────────────────────── -->
|
||||
<section class="hero" id="top">
|
||||
<div class="comb comb-deco"></div>
|
||||
<div class="eyebrow">A design concept for Waggle OS</div>
|
||||
<h1>The hive,<br><em>made calm.</em></h1>
|
||||
<p>Waggle is a genuinely powerful agent platform — persistent memory, model-agnostic orchestration, a swarm protocol. But today it speaks like an engineer and looks like a dashboard. This is a concept for making it feel <b style="color:var(--text)">premium, intuitive, and progressively revealed</b> — calm for the knowledge worker, with every ounce of power one keystroke away.</p>
|
||||
<div class="meta">
|
||||
<span class="pill">◆ Refreshed Hive identity</span>
|
||||
<span class="pill">◆ Landing page, Home, Chat & Workspace</span>
|
||||
<span class="pill">◆ Dark + light · interactive</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── THE READ ───────────────────────── -->
|
||||
<section id="read">
|
||||
<div class="eyebrow">The read</div>
|
||||
<h2 class="big">What's working —<br>and what's in the <em>way.</em></h2>
|
||||
<p class="lede">The bones are strong. The friction is in <b>density, language, and surface noise</b>. Five things stood out reading the live product.</p>
|
||||
|
||||
<div class="findings">
|
||||
<div class="finding">
|
||||
<div class="n">01</div>
|
||||
<div>
|
||||
<h3>The spine is overloaded</h3>
|
||||
<p>The left nav carries five zones and ~18 destinations before you've done anything. For a non-technical operator, that's a wall of choices — and the most important act, talking to your agent, is just one item among many.</p>
|
||||
<div class="obs">observed<b>18 nav items · 5 zones · always visible</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="finding">
|
||||
<div class="n">02</div>
|
||||
<div>
|
||||
<h3>It speaks fluent engineer</h3>
|
||||
<p>"Spawn agent", "Waggle-Dance", "MCPs", "GEPA", "consolidated memories". Power users get it; the operator you're designing for stalls. The product hides its own benefits behind its vocabulary.</p>
|
||||
<div class="obs">observed<b>jargon-first labels, no plain-language layer</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="finding">
|
||||
<div class="n">03</div>
|
||||
<div>
|
||||
<h3>Everything is small and the same size</h3>
|
||||
<p>The cockpit runs on 10–13px type with thin borders around every block. Nothing leads. It reads as a control panel, not a calm daily briefing — and it never feels premium at that density.</p>
|
||||
<div class="obs">observed<b>text-[10px]…[13px] · border on every card</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="finding">
|
||||
<div class="n">04</div>
|
||||
<div>
|
||||
<h3>Five colors shouting at once</h3>
|
||||
<p>Blue, purple, green, orange, red all fire simultaneously across the briefing, layered over glass, a wallpaper, and a honeycomb texture. The eye has no rest and no hierarchy to follow.</p>
|
||||
<div class="obs">observed<b>5 semantic hues + glass + wallpaper + comb</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="finding">
|
||||
<div class="n">05</div>
|
||||
<div>
|
||||
<h3>The magic stays hidden</h3>
|
||||
<p>Memory that compounds, work that happens overnight, agents that coordinate — these are the reasons to choose Waggle. They're present but buried in counters and lists. The differentiators never get a hero moment.</p>
|
||||
<div class="obs">observed<b>benefits expressed as small tallies</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── PRINCIPLES ───────────────────────── -->
|
||||
<section id="principles">
|
||||
<div class="eyebrow">The response</div>
|
||||
<h2 class="big">Five principles<br>for the <em>redesign.</em></h2>
|
||||
<p class="lede">Each one answers a finding above. They're the rules every screen in this concept follows.</p>
|
||||
|
||||
<div class="principles">
|
||||
<div class="principle">
|
||||
<div class="hexmark hex"></div>
|
||||
<div class="idx">01 ↦ findings 01·02</div>
|
||||
<h3>Calm by default,<br>powerful on demand</h3>
|
||||
<p>Show only what the moment needs. Swarm, MCPs, optimizer and the rest live behind one command bar — discoverable, never in the way. Progressive disclosure as the core mechanic.</p>
|
||||
</div>
|
||||
<div class="principle">
|
||||
<div class="hexmark hex"></div>
|
||||
<div class="idx">02 ↦ finding 01</div>
|
||||
<h3>One clear spine</h3>
|
||||
<p>Collapse 18 destinations into a handful of plain-language places, anchored on the conversation. Everything else is reachable from <span class="kbd">⌘K</span> — the OS, not the sidebar, holds the breadth.</p>
|
||||
</div>
|
||||
<div class="principle">
|
||||
<div class="hexmark hex"></div>
|
||||
<div class="idx">03 ↦ finding 05</div>
|
||||
<h3>Show the magic</h3>
|
||||
<p>Memory, overnight work and coordination get real estate and language a human understands. The differentiators become legible scenes, not tallies in a corner.</p>
|
||||
</div>
|
||||
<div class="principle">
|
||||
<div class="hexmark hex"></div>
|
||||
<div class="idx">04 ↦ findings 03·04</div>
|
||||
<h3>Warm & crafted</h3>
|
||||
<p>A warm graphite hive, one honey accent used with intent, an editorial serif for moments that matter, and air between things. Premium is restraint plus a real type hierarchy.</p>
|
||||
</div>
|
||||
<div class="principle" style="grid-column: 1 / -1;">
|
||||
<div class="hexmark hex"></div>
|
||||
<div class="idx">05 ↦ finding 02</div>
|
||||
<h3>Speak human, reveal the expert layer</h3>
|
||||
<p>Lead with plain words — "Start a task", "Working while you're away", "Team of agents". The technical name ("waggle-dance", "MCP server") rides along as a quiet subtitle for the power user. One product, two reading levels.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── IDENTITY ───────────────────────── -->
|
||||
<section id="identity">
|
||||
<div class="eyebrow">Identity</div>
|
||||
<h2 class="big">A warmer <em>hive.</em></h2>
|
||||
<p class="lede">Same DNA — honey, hexagons, the waggle dance — rebuilt for warmth and restraint. The cold blue-graphite becomes a warm graphite you'd want to live in; honey stops being decoration and becomes a precision accent; and one clean grotesk does the talking — <b>simple, not bookish</b>.</p>
|
||||
|
||||
<div class="sg-grid">
|
||||
<div class="panel">
|
||||
<p class="label">Surfaces · warm graphite → warm paper</p>
|
||||
<div class="swatches" id="surfSw"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<p class="label">Accent & refined semantics</p>
|
||||
<div class="swatches" id="accentSw" style="grid-template-columns:repeat(3,1fr)"></div>
|
||||
<div class="sem-row" id="semRow"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<p class="label">Type — one humanist grotesk, used with a real scale · mono for the technical layer</p>
|
||||
<div class="type-spec">
|
||||
<div class="row">
|
||||
<div class="k">Display<br>Hanken Grotesk 600</div>
|
||||
<div class="serif-demo">The hive, <em>made calm.</em></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="k">Interface<br>Hanken Grotesk 400–600</div>
|
||||
<div class="sans-demo">Start a task, and Waggle remembers.<small>One family, simple and modern — hierarchy comes from size and weight, not a second typeface.</small></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="k">Technical<br>JetBrains Mono</div>
|
||||
<div class="mono-demo">waggle-dance · 3 agents · mem://hive/2026-06 · ⌘K</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── NAVIGATION ───────────────────────── -->
|
||||
<section id="navigation">
|
||||
<div class="eyebrow">Navigation & IA</div>
|
||||
<h2 class="big">From a wall<br>to a <em>spine.</em></h2>
|
||||
<p class="lede">Eighteen always-on destinations become five plain-language places, with the long tail moved into the command bar. Toggle to compare.</p>
|
||||
|
||||
<div class="ia-toggle" id="iaToggle">
|
||||
<button data-ia="before">Today — 18 items</button>
|
||||
<button class="on" data-ia="after">Reimagined — 5 + ⌘K</button>
|
||||
</div>
|
||||
|
||||
<div class="ia-cols">
|
||||
<div class="navmock" id="navmock"></div>
|
||||
<div class="ia-note" id="iaNote"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────── IA / COMMAND BAR ───────────────────── -->
|
||||
<section id="ia">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">The spine, in practice</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Five places & a <em>command bar.</em></h2>
|
||||
<p class="lede">The live version of the IA above. A calm five-item sidebar; press <span class="kbd">⌘K</span> and the whole platform is searchable — swarm, MCP servers, optimizer, vault — each <b>named in plain language with the technical term underneath</b>. Power users can pin the tools they live in.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Calm spine</span>
|
||||
<span class="pill"><b>B</b> · Pro (pinned tools)</span>
|
||||
<span class="pill">Try ⌘K inside ↓</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/ia.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · navigation & ⌘K</span></div>
|
||||
<iframe src="screens/ia.html" title="Navigation & command bar" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── HOME ───────────────────────── -->
|
||||
<section id="landing">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">The public front door</div>
|
||||
<h2 class="big" style="margin-bottom:14px">The landing page, <em>rewritten.</em></h2>
|
||||
<p class="lede">A full redesign of waggle-os.ai — new identity, new content. It leads with the real story: <b>one local memory that feeds every model</b>, the proof that the layer (not the model) does the work, and honest free-forever pricing. No cartoon bees; the hive is a precise idea.</p>
|
||||
<div class="vary">
|
||||
<span class="pill">◆ New hive-memory hero</span>
|
||||
<span class="pill">◆ LoCoMo proof, made legible</span>
|
||||
<span class="pill">◆ Dark + light</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="Waggle Landing.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle-os.ai</span></div>
|
||||
<iframe src="Waggle Landing.html" title="Landing page redesign" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="home">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 01 · Home</div>
|
||||
<h2 class="big" style="margin-bottom:14px">The morning <em>briefing.</em></h2>
|
||||
<p class="lede">A calm scene that opens with one sentence of human language, surfaces what ran overnight as a story, and offers a single obvious next move.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Editorial briefing</span>
|
||||
<span class="pill"><b>B</b> · Focus / single-action</span>
|
||||
<span class="pill"><b>C</b> · Operator dashboard</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/home.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · home</span></div>
|
||||
<iframe src="screens/home.html" title="Home redesign" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── CHAT ───────────────────────── -->
|
||||
<section id="chat">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 02 · Chat runtime</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Where the work<br><em>happens.</em></h2>
|
||||
<p class="lede">The core surface. The conversation leads; the agent's thinking, tool calls, memory writes and approvals reveal progressively beside it — legible, never overwhelming.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Conversation-first</span>
|
||||
<span class="pill"><b>B</b> · Split work canvas</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/chat.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · workspace / chat</span></div>
|
||||
<iframe src="screens/chat.html" title="Chat redesign" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────────── WORKSPACE ───────────────────────── -->
|
||||
<section id="workspace">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 03 · Workspace</div>
|
||||
<h2 class="big" style="margin-bottom:14px">A place that <em>remembers.</em></h2>
|
||||
<p class="lede">The workspace makes Waggle's memory tangible — what it knows, what it made, who's working on what — without drowning you in tabs.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Overview + tabs</span>
|
||||
<span class="pill"><b>B</b> · Memory-forward</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/workspace.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · workspace</span></div>
|
||||
<iframe src="screens/workspace.html" title="Workspace redesign" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────── LAUNCHER ───────────────────── -->
|
||||
<section id="launcher">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 04 · Launcher · the feature I under-served</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Bring your own <em>agent.</em></h2>
|
||||
<p class="lede">Waggle can detect and launch Claude Code, Cursor, Codex, Hermes — and run them <b>wired into this workspace's memory</b>. The agent recalls what the hive knows and commits its work back, with provenance. The shipped screen calls itself “minimal-viable”; this makes it a first-class surface and explains the wiring.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Launch & manage</span>
|
||||
<span class="pill"><b>B</b> · How memory is shared</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/launcher.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · launch external agents</span></div>
|
||||
<iframe src="screens/launcher.html" title="External agent launcher" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────────── STORAGE ───────────────────── -->
|
||||
<section id="storage">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 05 · Storage · making the filesystem legible</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Where your work <em>lives.</em></h2>
|
||||
<p class="lede">A workspace can be <b>Virtual</b> (Waggle-managed), <b>Local</b> (a real folder on your machine), or <b>Team</b> (shared). Today that's invisible. This surface shows the exact path — memory db, files, artifacts — and what stays private, so “local-first” is something you can <i>see</i>.</p>
|
||||
<div class="vary">
|
||||
<span class="pill"><b>A</b> · Where it lives</span>
|
||||
<span class="pill"><b>B</b> · Files + provenance</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/storage.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · storage & files</span></div>
|
||||
<iframe src="screens/storage.html" title="Storage and files" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="surfaces">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 06 · the long tail, cleaned up</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Every power tool, <em>one template.</em></h2>
|
||||
<p class="lede">The surfaces that used to be 15 bespoke, half-finished screens — Tools & connectors, Automations, Approvals, Vault, Usage — rebuilt on <b>one consistent, functional pattern</b> and tucked behind ⌘K. Switch with the rail; toggles, approvals, and renewals all work.</p>
|
||||
<div class="vary">
|
||||
<span class="pill">Tools</span><span class="pill">Automations</span><span class="pill">Approvals</span><span class="pill">Vault</span><span class="pill">Usage</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="open" href="screens/surfaces.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="bar"><i></i><i></i><i></i><span class="u">waggle · power surfaces (⌘K)</span></div>
|
||||
<iframe src="screens/surfaces.html" title="Power surfaces" loading="lazy"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="workspaces">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 07 · answering “where are all my workspaces?”</div>
|
||||
<h2 class="big" style="margin-bottom:14px">The whole <em>shelf.</em></h2>
|
||||
<p class="lede">Home greets you with the day; <b>Workspaces</b> is every space you have — with its storage type (local / virtual / team), memory count, and what's live. Searchable, filterable, and reachable from the rail, ⌘K, or any workspace's switcher.</p>
|
||||
<div class="vary"><span class="pill"><b>Grid</b></span><span class="pill"><b>Table</b></span><span class="pill">search + storage filters</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/workspaces.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · all workspaces</span></div><iframe src="screens/workspaces.html" title="Workspaces index" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<section id="onboarding">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 08 · first run · the part I'd skipped</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Two minutes to <em>first value.</em></h2>
|
||||
<p class="lede">A five-step takeover: welcome → a little about you → import your history (locally) → pick a starting template → your first task. It ends <b>inside the work</b>, not on an empty screen. Step through it with the controls.</p>
|
||||
<div class="vary"><span class="pill">Welcome</span><span class="pill">About you</span><span class="pill">Import</span><span class="pill">Template</span><span class="pill">First task</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/onboarding.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · first-run onboarding</span></div><iframe src="screens/onboarding.html" title="Onboarding" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<section id="evolution">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 09 · the second moat</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Skills that <em>improve & spread.</em></h2>
|
||||
<p class="lede">Beyond memory: skills <b>re-optimize themselves</b> against real outcomes (versioned, judged, roll-back-able) and <b>diffuse across agents and workspaces</b> — the waggle dance. Tool setups spread the same way. The whole hive compounds.</p>
|
||||
<div class="vary"><span class="pill"><b>A</b> · Skills that improve</span><span class="pill"><b>B</b> · Skills & tools that spread</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/evolution.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · skill evolution & diffusion</span></div><iframe src="screens/evolution.html" title="Skill evolution" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── SETTINGS ────────────────────── -->
|
||||
<section id="settings">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 10 · Settings · calm, with a model gate</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Settings that <em>route themselves.</em></h2>
|
||||
<p class="lede">The whole settings surface rebuilt around progressive disclosure (Essential → Standard → Everything). The lead is <b>Models</b>: Waggle needs one working model, so it surfaces a <b>failover chain</b> — primary → fallback on error → a local/budget model when you hit your cap. The same model gate appears in onboarding, so first-run can't dead-end.</p>
|
||||
<div class="vary"><span class="pill"><b>Model pilot</b> + failover</span><span class="pill">Essential / Standard / Everything</span><span class="pill">Permissions · Plan · Backup</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/settings.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · settings</span></div><iframe src="screens/settings.html" title="Settings" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ───────────────── MARKETPLACE ────────────────── -->
|
||||
<section id="marketplace">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 11 · Marketplace · made simple & agent-searchable</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Capabilities, <em>without the catalog.</em></h2>
|
||||
<p class="lede">Skills, connectors, and MCP tools were three separate, jargon-heavy surfaces. Now they're <b>one shelf</b> — and you don't browse 400 cards, you <b>describe the job and the agent picks</b> (a connector to reach your data, a skill to do the work, the tool they need). The same picker also appears <b>inline in chat</b> the moment a task needs something you don't have.</p>
|
||||
<div class="vary"><span class="pill"><b>A</b> · Browse & ask the agent</span><span class="pill"><b>B</b> · Inline in chat</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/marketplace.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · marketplace</span></div><iframe src="screens/marketplace.html" title="Marketplace" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── AUTH ────────────────────── -->
|
||||
<section id="auth">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 12 · Front door · Clerk</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Getting in, <em>kept simple.</em></h2>
|
||||
<p class="lede">Sign-in, sign-up, email verification, and SSO — clean and on-brand, with an honest twist: <b>an account is optional</b>. Waggle runs fully local without one; you sign in only to sync across devices or join a team.</p>
|
||||
<div class="vary"><span class="pill">Sign in</span><span class="pill">Sign up</span><span class="pill">Verify (OTP)</span><span class="pill">SSO / enterprise</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/auth.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · auth (clerk)</span></div><iframe src="screens/auth.html" title="Auth" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── BILLING ────────────────────── -->
|
||||
<section id="billing">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 13 · Billing · Stripe</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Upgrading, <em>without friction.</em></h2>
|
||||
<p class="lede">Plans → checkout → success → manage, as a clean Stripe flow. Monthly/annual toggle, a trial-aware order summary, a real card form, and a billing portal with invoices. Honest pricing, no dark patterns.</p>
|
||||
<div class="vary"><span class="pill">Plans</span><span class="pill">Checkout</span><span class="pill">Success</span><span class="pill">Manage & invoices</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/billing.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · billing (stripe)</span></div><iframe src="screens/billing.html" title="Billing" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── HABIT ────────────────────── -->
|
||||
<section id="habit">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">The engagement layer · why it sticks</div>
|
||||
<h2 class="big" style="margin-bottom:14px">Built to pull you <em>back.</em></h2>
|
||||
<p class="lede">A product that compounds deserves a habit loop. Trigger → action → variable reward → investment, made concrete with a daily streak, a compounding-memory counter, "while you were away" wins, and earned nudges. <b>Momentum, not manipulation</b> — every loop is anchored to real value, and all of it can be turned off.</p>
|
||||
<div class="vary"><span class="pill">Streak</span><span class="pill">Compounding memory</span><span class="pill">Variable reward</span><span class="pill">Gentle nudges</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/habit.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · the habit loop</span></div><iframe src="screens/habit.html" title="Habit loop" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── APP SURFACES ────────────────────── -->
|
||||
<section id="appsurfaces">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Screen 14 · the queued surfaces, drawn</div>
|
||||
<h2 class="big" style="margin-bottom:14px">The rest of the <em>hive.</em></h2>
|
||||
<p class="lede">The six remaining app routes, on one consistent rail: <b>Agents</b> (your team of specialists), <b>Room</b> (work alongside agents live), <b>Artifacts</b> (everything made, with provenance), <b>Mission Control</b> (the hive's health), <b>Timeline</b> (one activity stream), and <b>Profile</b> (what Waggle knows about you).</p>
|
||||
<div class="vary"><span class="pill">Agents</span><span class="pill">Room</span><span class="pill">Artifacts</span><span class="pill">Mission Control</span><span class="pill">Timeline</span><span class="pill">Profile</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/appsurfaces.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · app surfaces</span></div><iframe src="screens/appsurfaces.html" title="App surfaces" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── BENCHMARKS ────────────────────── -->
|
||||
<section id="benchmark">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Positioning · benchmarking</div>
|
||||
<h2 class="big" style="margin-bottom:14px">They automate tasks.<br>Waggle <em>remembers you.</em></h2>
|
||||
<p class="lede">An honest read against the field — <b>Claude Code, Codex, Claude Cowork, Hermes, Odysseus</b>. They're terminal task-agents for engineers; Waggle is a persistent, local-first memory layer that even <b>launches them</b>. Plus the one real head-to-head: the LoCoMo memory SOTA (87.66%).</p>
|
||||
<div class="vary"><span class="pill"><b>A</b> · Capability matrix</span><span class="pill"><b>B</b> · Memory SOTA</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/benchmark.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · benchmarks</span></div><iframe src="screens/benchmark.html" title="Benchmarks" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── PLATFORM ────────────────────── -->
|
||||
<section id="platform">
|
||||
<div class="screen-head">
|
||||
<div>
|
||||
<div class="eyebrow">Platform · ships in Tauri · what's next</div>
|
||||
<h2 class="big" style="margin-bottom:14px">One hive, <em>everywhere.</em></h2>
|
||||
<p class="lede">Waggle ships as a native <b>Tauri desktop app for Windows & macOS</b> — tiny, local, auto-updating. This covers the boot splash and 404 too, and lays out the roadmap: a browser extension in beta, and <b>messaging (WhatsApp, Telegram) + mobile coming next</b>.</p>
|
||||
<div class="vary"><span class="pill">Desktop (now)</span><span class="pill">Boot</span><span class="pill">Coming next</span><span class="pill">404</span></div>
|
||||
</div>
|
||||
<a class="open" href="screens/platform.html">Open full screen ↗</a>
|
||||
</div>
|
||||
<div class="frame"><div class="bar"><i></i><i></i><i></i><span class="u">waggle · platform & roadmap</span></div><iframe src="screens/platform.html" title="Platform" loading="lazy"></iframe></div>
|
||||
</section>
|
||||
|
||||
<!-- ─────────────────────── COVERAGE MAP ────────────────────── -->
|
||||
<section id="coverage">
|
||||
<div class="eyebrow">Monorepo coverage</div>
|
||||
<h2 class="big">The whole surface, <em>mapped.</em></h2>
|
||||
<p class="lede">Every route in the app's router, every OS app, and the front-of-app + payment + auth surfaces — with honest status. Click any <b>designed</b> one to jump to it.</p>
|
||||
<div class="covlegend">
|
||||
<span><span class="cst done"></span><b style="color:var(--text-2)">Designed</b> — has its own screen here</span>
|
||||
<span><span class="cst within"></span>Covered inside another screen</span>
|
||||
<span><span class="cst next"></span>Coming next · messaging & mobile</span>
|
||||
</div>
|
||||
<div class="cov" id="cov"></div>
|
||||
</section>
|
||||
|
||||
<div class="close-cta">
|
||||
<h2>The bones are <em>strong.</em></h2>
|
||||
<p>This concept keeps everything Waggle can do and changes how it feels to do it. Pick the directions that resonate and I'll take them deeper.</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>WAGGLE · CONCEPT EXPLORATION · 2026 — not affiliated visual identity, a proposal</footer>
|
||||
|
||||
<script>
|
||||
/* ── Theme ──────────────────────────────────────────────────────── */
|
||||
const root = document.documentElement, tbtn = document.getElementById('themebtn');
|
||||
function applyTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t === 'dark' ? '☾' : '☀'; localStorage.setItem('waggle-concept-theme', t); }
|
||||
applyTheme(localStorage.getItem('waggle-concept-theme') || 'dark');
|
||||
tbtn.onclick = () => applyTheme(root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
|
||||
|
||||
/* ── Swatches ───────────────────────────────────────────────────── */
|
||||
const surf = [['Background','--bg'],['Surface','--surface'],['Surface 2','--surface-2'],['Line','--line'],['Text','--text'],['Muted','--text-muted']];
|
||||
const acc = [['Honey','--honey'],['Bright','--honey-bright'],['Deep','--honey-deep']];
|
||||
const sem = [['Work','--work'],['Intelligence','--intel'],['Healthy','--healthy'],['Attention','--attention'],['Risk','--risk']];
|
||||
function swHTML(list){ return list.map(([n,v])=>`<div class="sw"><div class="chip" style="background:var(${v})"></div><div class="meta"><b>${n}</b><span>${v}</span></div></div>`).join(''); }
|
||||
document.getElementById('surfSw').innerHTML = swHTML(surf);
|
||||
document.getElementById('accentSw').innerHTML = swHTML(acc);
|
||||
document.getElementById('semRow').innerHTML = sem.map(([n,v])=>`<span class="pill" style="border-color:color-mix(in srgb, var(${v}) 45%, var(--line))"><span class="dot" style="background:var(${v})"></span>${n}</span>`).join('');
|
||||
|
||||
/* ── IA before / after ──────────────────────────────────────────── */
|
||||
const before = {
|
||||
zones: [
|
||||
['Work', [['Home',1],['Workspaces',0],['Memory',0],['Artifacts',0],['Files',0]]],
|
||||
['Intelligence', [['Agents',0],['Automations',0],['Skills',0],['Room',0],['Waggle-Dance',0],['Approvals',0]]],
|
||||
['Extend', [['Connectors',0],['MCPs',0],['Marketplace',0],['Launcher',0]]],
|
||||
['System', [['Settings',0],['Vault',0],['Mission Control',0]]],
|
||||
],
|
||||
more: '+ New Agent · Timeline · Events · Usage · Profile',
|
||||
note: {
|
||||
h: 'Today: breadth, up front',
|
||||
p: 'Everything the platform can do is exposed as a permanent list. It\u2019s honest about scope, but it asks the operator to parse 18 labels — many of them jargon — before doing a single thing.',
|
||||
li: [
|
||||
['18','destinations across <b>5 zones</b>, always visible'],
|
||||
['5','of them are power-user surfaces a novice never needs day one'],
|
||||
['Jx','labels like <b>Waggle-Dance</b>, <b>MCPs</b>, <b>Approvals</b> carry no plain meaning'],
|
||||
],
|
||||
},
|
||||
};
|
||||
const after = {
|
||||
zones: [
|
||||
['', [['Home',1],['Chat',0],['Memory',0],['Agents & tasks',0],['Library',0]]],
|
||||
],
|
||||
more: '⌘K · everything else lives here',
|
||||
note: {
|
||||
h: 'Reimagined: a spine + a command bar',
|
||||
p: 'Five plain-language places cover 95% of days. The long tail \u2014 connectors, MCP servers, the swarm protocol, optimizer, vault, usage \u2014 moves into ⌘K, where it\u2019s searchable the instant you need it and invisible when you don\u2019t.',
|
||||
li: [
|
||||
['5','everyday destinations, named for what you do, not how it\u2019s built'],
|
||||
['⌘K','one command bar holds the full depth \u2014 power without the wall'],
|
||||
['↳','technical names ride along as subtitles for the expert layer'],
|
||||
],
|
||||
},
|
||||
};
|
||||
function renderIA(state){
|
||||
const d = state === 'before' ? before : after;
|
||||
const nm = document.getElementById('navmock');
|
||||
nm.innerHTML = d.zones.map(([z, items]) =>
|
||||
(z ? `<div class="zone">${z}</div>` : '') +
|
||||
items.map(([label, on]) => `<div class="item ${on?'on':''} ${state==='before' && /Waggle-Dance|MCPs|Approvals|Mission Control|Vault/.test(label)?'muted':''}"><span class="ic"></span>${label}</div>`).join('')
|
||||
).join('') + `<div class="more">${d.more}</div>`;
|
||||
document.getElementById('iaNote').innerHTML =
|
||||
`<h3>${d.note.h}</h3><p>${d.note.p}</p><ul>${d.note.li.map(([b,t])=>`<li><span class="b">${b}</span><span>${t}</span></li>`).join('')}</ul>`;
|
||||
}
|
||||
const iaT = document.getElementById('iaToggle');
|
||||
iaT.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...iaT.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
renderIA(b.dataset.ia);
|
||||
});
|
||||
renderIA('after');
|
||||
|
||||
/* ── Coverage map ───────────────────────────────────────────────── */
|
||||
const COV = [
|
||||
['Front of app', [
|
||||
['Boot / splash','tauri','done','#platform'], ['Onboarding','first-run','done','#onboarding'],
|
||||
['Sign in / up','clerk','done','#auth'], ['Email verify','clerk','done','#auth'],
|
||||
['SSO / enterprise','clerk','done','#auth'], ['404 / not found','*','done','#platform'],
|
||||
]],
|
||||
['Work', [
|
||||
['Home / Cockpit','/home','done','#home'], ['All workspaces','/workspaces','done','#workspaces'],
|
||||
['Workspace','/workspaces/:id','done','#workspace'], ['Memory center','/memory','within','#workspace'],
|
||||
['Files / Storage','/files','done','#storage'], ['Artifacts','/artifacts','done','#appsurfaces'],
|
||||
]],
|
||||
['Intelligence', [
|
||||
['Agents','/agents','done','#appsurfaces'], ['Automations','/automations','done','#surfaces'],
|
||||
['Skills','/skills','done','#marketplace'], ['Approvals','/approvals','done','#surfaces'],
|
||||
['Room','/room','done','#appsurfaces'], ['Waggle-Dance / swarm','/waggle-dance','within','#evolution'],
|
||||
]],
|
||||
['Extend', [
|
||||
['Marketplace','/marketplace','done','#marketplace'], ['Connectors','/connectors','done','#marketplace'],
|
||||
['MCP servers','/mcps','done','#marketplace'], ['Launcher','/launcher','done','#launcher'],
|
||||
['Skill evolution','—','done','#evolution'],
|
||||
]],
|
||||
['System & account', [
|
||||
['Settings','/settings','done','#settings'], ['Models + failover','/settings','done','#settings'],
|
||||
['Vault','/settings/vault','done','#surfaces'], ['Usage & cost','/settings/usage','done','#surfaces'],
|
||||
['Billing','stripe','done','#billing'], ['Profile','/settings/profile','done','#appsurfaces'],
|
||||
['Team','/team','within','#settings'], ['Mission Control','/settings/mission-control','done','#appsurfaces'],
|
||||
['Timeline','/settings/timeline','done','#appsurfaces'], ['Events','/settings/events','done','#appsurfaces'],
|
||||
]],
|
||||
['Platform & roadmap', [
|
||||
['Desktop · Tauri','win + mac','done','#platform'], ['Browser extension','apps/browser-ext','beta','#platform'],
|
||||
['Messaging','whatsapp · telegram','next','#platform'], ['Mobile','ios · android','next','#platform'],
|
||||
]],
|
||||
['Cross-cutting', [
|
||||
['Benchmarks','vs the field','done','#benchmark'], ['Command bar ⌘K','—','done','#ia'], ['Design system','—','done','#identity'],
|
||||
['Habit loop','—','done','#habit'], ['Landing (www)','waggle-os.ai','done','#landing'],
|
||||
]],
|
||||
];
|
||||
document.getElementById('cov').innerHTML = COV.map(([zone, items]) => `
|
||||
<div class="covzone">
|
||||
<h3>${zone}</h3>
|
||||
<div class="covgrid">${items.map(([n, route, st, href]) => {
|
||||
const inner = `<span class="cst ${st}"></span><span class="cn">${st==='done'?`<b>${n}</b>`:n}</span><span class="croute">${route}</span>`;
|
||||
return href ? `<a class="covitem" href="${href}">${inner}</a>` : `<div class="covitem">${inner}</div>`;
|
||||
}).join('')}</div>
|
||||
</div>`).join('');
|
||||
|
||||
/* ── Active section highlight ───────────────────────────────────── */
|
||||
const links = [...document.querySelectorAll('#topnav a')];
|
||||
const map = links.map(a => ({a, sec: document.querySelector(a.getAttribute('href'))})).filter(x=>x.sec);
|
||||
const io = new IntersectionObserver(es => {
|
||||
es.forEach(e => { if(e.isIntersecting){ links.forEach(l=>l.classList.remove('on')); const m = map.find(x=>x.sec===e.target); if(m) m.a.classList.add('on'); } });
|
||||
}, { rootMargin: '-45% 0px -50% 0px' });
|
||||
map.forEach(x => io.observe(x.sec));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,250 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · App surfaces</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
|
||||
.controls { flex:none; display:flex; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line-soft); background:color-mix(in srgb,var(--bg) 88%,transparent); backdrop-filter:blur(10px); z-index:30; }
|
||||
.controls .lab { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); }
|
||||
.controls .vlabel { font-size:12.5px; color:var(--text-muted); } .controls .vlabel b { color:var(--text); font-weight:600; }
|
||||
.controls .right { margin-left:auto; display:flex; align-items:center; gap:10px; }
|
||||
.tbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--surface); color:var(--text-2); cursor:pointer; }
|
||||
.tbtn:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.app { flex:1; min-height:0; display:flex; }
|
||||
.rail { flex:none; width:208px; border-right:1px solid var(--line-soft); background:var(--bg-2); padding:16px 10px; overflow:auto; }
|
||||
.rail .rh { font-family:var(--mono); font-size:10px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); padding:6px 11px 12px; }
|
||||
.ritem { display:flex; align-items:center; gap:11px; padding:9px 11px; border-radius:10px; cursor:pointer; color:var(--text-2); transition:.13s; font-size:13.5px; font-weight:550; position:relative; }
|
||||
.ritem:hover { background:var(--surface-2); color:var(--text); }
|
||||
.ritem.on { background:var(--honey-wash); color:var(--text); }
|
||||
.ritem.on::before { content:''; position:absolute; left:-10px; top:50%; transform:translateY(-50%); width:3px; height:17px; border-radius:3px; background:var(--honey); }
|
||||
.ritem svg { width:17px; height:17px; stroke:currentColor; fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; flex:none; }
|
||||
.ritem.on svg { stroke:var(--honey); }
|
||||
.ritem .ct { margin-left:auto; font-family:var(--mono); font-size:10px; color:var(--text-dim); }
|
||||
.rail .rz { font-family:var(--mono); font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); padding:16px 11px 6px; }
|
||||
|
||||
.main { flex:1; min-width:0; display:flex; flex-direction:column; }
|
||||
.shead { flex:none; display:flex; align-items:flex-start; gap:16px; padding:24px 30px 16px; border-bottom:1px solid var(--line-soft); }
|
||||
.shead h1 { font-size:21px; font-weight:650; letter-spacing:-0.02em; margin:0 0 4px; }
|
||||
.shead p { font-size:13px; color:var(--text-muted); margin:0; max-width:62ch; line-height:1.5; }
|
||||
.shead .pa { margin-left:auto; font-size:12.5px; font-weight:650; padding:9px 15px; border-radius:9px; background:var(--honey); color:#1a1407; cursor:pointer; white-space:nowrap; border:0; display:inline-flex; align-items:center; gap:7px; }
|
||||
.shead .pa:hover { background:var(--honey-bright); }
|
||||
.body { flex:1; min-height:0; overflow:auto; padding:22px 30px 50px; }
|
||||
.panel { display:none; } .panel.on { display:block; }
|
||||
|
||||
.grp { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); margin:4px 0 12px; display:flex; align-items:center; gap:10px; } .grp:not(:first-child){ margin-top:26px; } .grp::after { content:''; flex:1; height:1px; background:var(--line-soft); }
|
||||
.rows { display:grid; gap:9px; }
|
||||
.rc { display:flex; align-items:center; gap:14px; padding:14px 16px; border-radius:var(--r); border:1px solid var(--line-soft); background:var(--surface); transition:.14s; }
|
||||
.rc:hover { border-color:var(--line-strong); }
|
||||
.rc .ri { width:34px; height:38px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:700; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.rc .ri.soft { color:var(--text-2); background:var(--surface-2); border:1px solid var(--line); }
|
||||
.rc .rt { flex:1; min-width:0; } .rc .rt b { font-size:14.5px; font-weight:600; } .rc .rt .rs { font-size:12.5px; color:var(--text-muted); margin-top:2px; } .rc .rt .rs .mono { font-family:var(--mono); font-size:11.5px; color:var(--text-dim); } .rc .rt .rs .prov { color:var(--intel); }
|
||||
.rc .meta { font-family:var(--mono); font-size:11px; color:var(--text-dim); white-space:nowrap; }
|
||||
.bdg { font-size:11px; font-weight:600; padding:3px 9px; border-radius:999px; display:inline-flex; align-items:center; gap:5px; white-space:nowrap; }
|
||||
.bdg.live { color:var(--healthy); background:var(--healthy-wash); } .bdg.idle { color:var(--text-dim); background:var(--surface-2); } .bdg.warn { color:var(--attention); background:var(--honey-wash); } .bdg.work { color:var(--work); background:var(--work-wash); }
|
||||
.lnk { font-size:12px; font-weight:600; color:var(--text-2); cursor:pointer; } .lnk:hover { color:var(--honey); }
|
||||
|
||||
/* grid cards (artifacts) */
|
||||
.cards { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
|
||||
.acard { border:1px solid var(--line-soft); background:var(--surface); border-radius:var(--r-lg); padding:16px; cursor:pointer; transition:.15s; }
|
||||
.acard:hover { border-color:var(--honey-line); transform:translateY(-2px); box-shadow:var(--shadow); }
|
||||
.acard .ext { width:38px; height:42px; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:700; border-radius:8px; margin-bottom:12px; }
|
||||
.acard h4 { font-size:14px; font-weight:600; margin:0 0 4px; } .acard .am { font-size:11.5px; color:var(--text-dim); font-family:var(--mono); } .acard .prov { font-size:11px; color:var(--intel); margin-top:9px; }
|
||||
|
||||
/* profile */
|
||||
.profhead { display:flex; align-items:center; gap:16px; margin-bottom:22px; }
|
||||
.profhead .pa2 { width:60px; height:66px; flex:none; display:grid; place-items:center; font-weight:800; font-size:24px; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.profhead h2 { font-size:22px; font-weight:650; margin:0; letter-spacing:-0.02em; } .profhead .ph2 { font-size:13px; color:var(--text-muted); margin-top:3px; }
|
||||
.chips { display:flex; flex-wrap:wrap; gap:8px; }
|
||||
.chip { font-size:12.5px; font-weight:550; padding:6px 13px; border-radius:999px; border:1px solid var(--line-soft); background:var(--surface); color:var(--text-2); }
|
||||
.chip.on { background:var(--honey-wash); border-color:var(--honey-line); color:var(--honey); }
|
||||
.knows { display:grid; gap:9px; }
|
||||
.kfact { display:grid; grid-template-columns:18px 1fr; gap:11px; padding:12px 14px; border-radius:var(--r); border:1px solid var(--line-soft); background:var(--surface); font-size:13.5px; color:var(--text); }
|
||||
.kfact .kd { color:var(--honey); }
|
||||
|
||||
/* mission control */
|
||||
.mc-stat { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:22px; }
|
||||
.mcs { padding:16px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); }
|
||||
.mcs .v { font-size:24px; font-weight:750; letter-spacing:-0.02em; } .mcs .l { font-size:11.5px; color:var(--text-muted); margin-top:5px; }
|
||||
.svc { display:flex; align-items:center; gap:12px; padding:12px 0; border-bottom:1px solid var(--line-soft); font-size:13.5px; } .svc:last-child { border-bottom:0; } .svc .sd { width:8px; height:8px; border-radius:999px; flex:none; } .svc .sn { flex:1; } .svc .sm { font-family:var(--mono); font-size:11px; color:var(--text-dim); }
|
||||
|
||||
/* timeline */
|
||||
.tl { display:grid; grid-template-columns:74px 1fr; gap:16px; padding:13px 0; border-top:1px solid var(--line-soft); } .tl:first-child { border-top:0; }
|
||||
.tl .when { font-family:var(--mono); font-size:11px; color:var(--text-dim); padding-top:2px; }
|
||||
.tl .ev { font-size:13.5px; color:var(--text-2); line-height:1.5; } .tl .ev b { color:var(--text); font-weight:600; } .tl .ev .src { font-family:var(--mono); font-size:10.5px; margin-left:6px; }
|
||||
.tl .ev .src.mem { color:var(--intel); } .tl .ev .src.web { color:var(--work); } .tl .ev .src.sys { color:var(--text-dim); } .tl .ev .src.ok { color:var(--healthy); }
|
||||
|
||||
/* room */
|
||||
.room { display:grid; grid-template-columns:1fr 260px; gap:16px; }
|
||||
.roomstage { border:1px solid var(--line-soft); border-radius:var(--r-xl); background:var(--bg-2); padding:22px; min-height:280px; position:relative; overflow:hidden; }
|
||||
.roomstage .comb { position:absolute; inset:0; opacity:.4; }
|
||||
.live-act { position:relative; display:grid; gap:10px; }
|
||||
.la { display:flex; gap:11px; align-items:flex-start; padding:12px 14px; border-radius:var(--r); background:var(--surface); border:1px solid var(--line-soft); }
|
||||
.la .av { width:28px; height:32px; flex:none; display:grid; place-items:center; font-size:11px; font-weight:700; }
|
||||
.la .av.you { background:var(--surface-3); color:var(--text-2); border-radius:8px; } .la .av.bot { color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.la .lc b { font-size:13px; font-weight:650; } .la .lc p { margin:3px 0 0; font-size:12.5px; color:var(--text-muted); line-height:1.45; }
|
||||
.participants { border:1px solid var(--line-soft); border-radius:var(--r-lg); background:var(--surface); padding:16px; }
|
||||
.participants h4 { font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-dim); margin:0 0 12px; }
|
||||
.pp { display:flex; align-items:center; gap:10px; padding:7px 0; font-size:13px; } .pp .pd { width:7px; height:7px; border-radius:999px; } .pp .pn { flex:1; } .pp .pr { font-size:11px; color:var(--text-dim); }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width:820px){ .rail { width:62px; } .rail .rh, .rail .rz, .ritem span.txt, .ritem .ct { display:none; } .cards, .mc-stat { grid-template-columns:1fr 1fr; } .room { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">App surfaces · queued screens, now drawn</span>
|
||||
<span class="vlabel" id="vlabel"><b>Agents</b> — your team of specialists</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="app">
|
||||
<nav class="rail" id="rail">
|
||||
<div class="rz">Intelligence</div>
|
||||
<div class="ritem on" data-s="agents"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9z"/></svg><span class="txt">Agents</span><span class="ct">4</span></div>
|
||||
<div class="ritem" data-s="room"><svg viewBox="0 0 24 24"><circle cx="9" cy="8" r="3"/><path d="M3.5 19a5.5 5.5 0 0 1 11 0M16 6a3 3 0 0 1 0 6"/></svg><span class="txt">Room</span><span class="ct live" style="color:var(--healthy)">●</span></div>
|
||||
<div class="rz">Work</div>
|
||||
<div class="ritem" data-s="artifacts"><svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6"/></svg><span class="txt">Artifacts</span><span class="ct">7</span></div>
|
||||
<div class="rz">System</div>
|
||||
<div class="ritem" data-s="mission"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg><span class="txt">Mission Control</span></div>
|
||||
<div class="ritem" data-s="timeline"><svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h10"/></svg><span class="txt">Timeline</span></div>
|
||||
<div class="ritem" data-s="profile"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M5.5 21a7 7 0 0 1 13 0"/></svg><span class="txt">Profile</span></div>
|
||||
</nav>
|
||||
|
||||
<div class="main">
|
||||
<div class="shead">
|
||||
<div><h1 id="sTitle">Agents</h1><p id="sSub">Your team of specialists — each with a persona, a model, and a memory of its work.</p></div>
|
||||
<button class="pa" id="sAction"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg><span id="sActionT">New agent</span></button>
|
||||
</div>
|
||||
<div class="body" id="body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const head = {
|
||||
agents:['Agents','Your team of specialists — each with a persona, a model, and a memory of its work.','New agent'],
|
||||
room:['Room','Work alongside your agents live — shared context, real-time.','Invite'],
|
||||
artifacts:['Artifacts','Everything you and your agents have made — with provenance and versions.','New'],
|
||||
mission:['Mission Control','The health of your hive — services, agents, memory, sync.','Diagnostics'],
|
||||
timeline:['Timeline','One stream of everything that happened, across every workspace.','Filter'],
|
||||
profile:['Profile','What Waggle knows about you — so every agent works the way you do.','Edit'],
|
||||
};
|
||||
function rc(icon, title, sub, right, soft){ return `<div class="rc"><div class="ri ${soft?'soft':''}">${icon}</div><div class="rt"><b>${title}</b><div class="rs">${sub}</div></div>${right||''}</div>`; }
|
||||
|
||||
const panels = {
|
||||
agents: () => `
|
||||
<div class="grp">Working now</div>
|
||||
<div class="rows">
|
||||
${rc('R','Research-synth','<span class="rs">Analyst persona · Claude Sonnet · <span class="prov">Competitive Intelligence</span></span>','<div style="display:flex;gap:10px;align-items:center"><span class="bdg live"><span class="dot dot-live" style="background:var(--healthy)"></span>theming · 78%</span><span class="lnk">Open</span></div>')}
|
||||
${rc('D','Deck-builder','<span class="rs">Designer persona · GPT-4o · <span class="prov">Q2 Board Deck</span></span>','<div style="display:flex;gap:10px;align-items:center"><span class="bdg work">waiting on you</span><span class="lnk">Open</span></div>')}
|
||||
</div>
|
||||
<div class="grp">Idle · ready</div>
|
||||
<div class="rows">
|
||||
${rc('W','Writer','<span class="rs">Writing persona · auto · last ran 2d ago</span>','<span class="bdg idle">idle</span>')}
|
||||
${rc('A','Analyst','<span class="rs">Finance persona · local model · last ran 3d ago</span>','<span class="bdg idle">idle</span>')}
|
||||
</div>
|
||||
<div class="grp">Want more hands?</div>
|
||||
${rc('<svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--honey)" stroke-width=1.8><circle cx=6 cy=7 r=2.4/><circle cx=18 cy=7 r=2.4/><circle cx=12 cy=17 r=2.4/><path d="M8 8l3 7M16 8l-3 7"/></svg>','Run a team of agents','<span class="rs">waggle-dance · let several specialists coordinate on one goal</span>','<span class="lnk">Start a swarm →</span>', true)}`,
|
||||
|
||||
room: () => `
|
||||
<div class="room">
|
||||
<div class="roomstage">
|
||||
<div class="comb"></div>
|
||||
<div class="live-act">
|
||||
<div class="la"><div class="av you">You</div><div class="lc"><b>You</b><p>Let's get the board narrative tight — focus on the regulated-industries angle.</p></div></div>
|
||||
<div class="la"><div class="av bot hex">R</div><div class="lc"><b>Research-synth</b><p>Pulling the 3 strongest proof points from memory and the teardown… two cite customer quotes.</p></div></div>
|
||||
<div class="la"><div class="av bot hex">D</div><div class="lc"><b>Deck-builder</b><p>Drafting slide 6 around that angle now — I'll show you a version in ~30s.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="participants">
|
||||
<h4>In the room</h4>
|
||||
<div class="pp"><span class="pd" style="background:var(--honey)"></span><span class="pn">You</span><span class="pr">host</span></div>
|
||||
<div class="pp"><span class="pd dot-live" style="background:var(--healthy)"></span><span class="pn">Research-synth</span><span class="pr">live</span></div>
|
||||
<div class="pp"><span class="pd dot-live" style="background:var(--healthy)"></span><span class="pn">Deck-builder</span><span class="pr">live</span></div>
|
||||
<div class="pp"><span class="pd" style="background:var(--text-dim)"></span><span class="pn">Jonas P.</span><span class="pr">invited</span></div>
|
||||
<div style="margin-top:14px;font-size:12px;color:var(--text-muted);line-height:1.5">Everyone shares this workspace's memory. Voice is one tap away.</div>
|
||||
</div>
|
||||
</div>`,
|
||||
|
||||
artifacts: () => `
|
||||
<div class="grp">Recent · Competitive Intelligence</div>
|
||||
<div class="cards">
|
||||
<div class="acard"><div class="ext" style="background:var(--work-wash);color:var(--work)">MD</div><h4>teardown.md</h4><div class="am">48 KB · v3</div><div class="prov">⬡ made by Waggle</div></div>
|
||||
<div class="acard"><div class="ext" style="background:var(--healthy-wash);color:var(--healthy)">XLS</div><h4>pricing-landscape.xlsx</h4><div class="am">126 KB · v2</div><div class="prov">⬡ made by Waggle</div></div>
|
||||
<div class="acard"><div class="ext" style="background:var(--intel-wash);color:var(--intel)">MD</div><h4>board-brief.md</h4><div class="am">22 KB · v1</div><div class="prov">⬡ made by Claude Code</div></div>
|
||||
<div class="acard"><div class="ext" style="background:var(--risk-wash);color:var(--risk)">PDF</div><h4>mem0-teardown.pdf</h4><div class="am">1.4 MB</div><div class="prov" style="color:var(--text-dim)">you uploaded</div></div>
|
||||
<div class="acard"><div class="ext" style="background:var(--work-wash);color:var(--work)">PNG</div><h4>landscape-chart.png</h4><div class="am">340 KB</div><div class="prov">⬡ made by Waggle</div></div>
|
||||
<div class="acard"><div class="ext" style="background:var(--honey-wash);color:var(--honey)">PPT</div><h4>q2-board.pptx</h4><div class="am">2.1 MB · v4</div><div class="prov">⬡ made by Waggle</div></div>
|
||||
</div>`,
|
||||
|
||||
mission: () => `
|
||||
<div class="mc-stat">
|
||||
<div class="mcs"><div class="v" style="color:var(--healthy)">●</div><div class="l">All systems healthy</div></div>
|
||||
<div class="mcs"><div class="v">2</div><div class="l">Agents running</div></div>
|
||||
<div class="mcs"><div class="v" style="color:var(--intel)">581</div><div class="l">Memories (all hives)</div></div>
|
||||
<div class="mcs"><div class="v">58ms</div><div class="l">Avg recall</div></div>
|
||||
</div>
|
||||
<div class="grp">Local services</div>
|
||||
<div class="rows" style="padding:4px 0">
|
||||
<div class="svc"><span class="sd dot-live" style="background:var(--healthy)"></span><span class="sn">Memory engine <span style="color:var(--text-dim)">· hive-mind</span></span><span class="sm">SQLite · 581 rows · ok</span></div>
|
||||
<div class="svc"><span class="sd dot-live" style="background:var(--healthy)"></span><span class="sn">Agent runtime</span><span class="sm">2 active · ok</span></div>
|
||||
<div class="svc"><span class="sd dot-live" style="background:var(--healthy)"></span><span class="sn">Local model <span style="color:var(--text-dim)">· Qwen 2.5</span></span><span class="sm">Ollama · ok</span></div>
|
||||
<div class="svc"><span class="sd" style="background:var(--attention)"></span><span class="sn">Salesforce sync</span><span class="sm" style="color:var(--attention)">auth expired · fix</span></div>
|
||||
<div class="svc"><span class="sd" style="background:var(--text-dim)"></span><span class="sn">Team sync</span><span class="sm">not connected</span></div>
|
||||
</div>`,
|
||||
|
||||
timeline: () => `
|
||||
<div class="grp">Today</div>
|
||||
<div>
|
||||
<div class="tl"><div class="when">08:42</div><div class="ev">You opened <b>Competitive Intelligence</b><span class="src sys">⬡ session</span></div></div>
|
||||
<div class="tl"><div class="when">02:40</div><div class="ev"><b>Teardown</b> finished overnight · 9 competitors<span class="src ok">⬡ agent</span></div></div>
|
||||
<div class="tl"><div class="when">02:14</div><div class="ev">Salesforce export <b>failed</b> · auth expired<span class="src" style="color:var(--risk)">⬡ automation</span></div></div>
|
||||
<div class="tl"><div class="when">02:05</div><div class="ev">Folded <b>14 memories</b> into the hive<span class="src mem">⬡ mem</span></div></div>
|
||||
</div>
|
||||
<div class="grp">Yesterday</div>
|
||||
<div>
|
||||
<div class="tl"><div class="when">16:30</div><div class="ev">Learned <b>Mem0 changed pricing</b><span class="src web">⬡ web</span></div></div>
|
||||
<div class="tl"><div class="when">11:10</div><div class="ev"><b>Deck-builder</b> drafted 18 slides<span class="src ok">⬡ agent</span></div></div>
|
||||
</div>`,
|
||||
|
||||
profile: () => `
|
||||
<div class="profhead"><div class="pa2 hex">M</div><div><h2>Mara Kovač</h2><div class="ph2">Strategy · solo · Pro trial · mara@egzakta.com</div></div></div>
|
||||
<div class="grp">How I like to work <span style="text-transform:none;letter-spacing:0;color:var(--text-dim)">— every agent reads this</span></div>
|
||||
<div class="chips" style="margin-bottom:6px">
|
||||
<span class="chip on">Direct, no fluff</span><span class="chip on">Lead with the recommendation</span><span class="chip on">Always cite sources</span><span class="chip">Metric over narrative</span><span class="chip">+ add</span>
|
||||
</div>
|
||||
<div class="grp">What Waggle knows about me</div>
|
||||
<div class="knows">
|
||||
<div class="kfact"><span class="kd">⬡</span><div>Works in <b>competitive strategy</b>; reports up to a board quarterly.</div></div>
|
||||
<div class="kfact"><span class="kd">⬡</span><div>Prefers <b>regulated-industries framing</b> in market work.</div></div>
|
||||
<div class="kfact"><span class="kd">⬡</span><div>Trusts <b>local-first</b>; sensitive about data leaving the machine.</div></div>
|
||||
</div>
|
||||
<div class="grp">Expertise · personas you can speak as</div>
|
||||
<div class="chips"><span class="chip">Strategist</span><span class="chip">Analyst</span><span class="chip">Writer</span><span class="chip">Editor</span></div>`,
|
||||
};
|
||||
|
||||
function show(s){
|
||||
document.querySelectorAll('.ritem').forEach(r=>r.classList.toggle('on', r.dataset.s===s));
|
||||
document.getElementById('sTitle').textContent = head[s][0];
|
||||
document.getElementById('sSub').textContent = head[s][1];
|
||||
document.getElementById('sActionT').textContent = head[s][2];
|
||||
document.getElementById('vlabel').innerHTML = '<b>'+head[s][0]+'</b> — '+({agents:'your team of specialists',room:'work with agents live',artifacts:'everything you\u2019ve made',mission:'the health of your hive',timeline:'everything that happened',profile:'what Waggle knows about you'})[s];
|
||||
document.getElementById('body').innerHTML = panels[s]();
|
||||
document.getElementById('body').scrollTop = 0;
|
||||
}
|
||||
document.getElementById('rail').addEventListener('click', e=>{ const r=e.target.closest('.ritem'); if(r) show(r.dataset.s); });
|
||||
show('agents');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
180
docs/design_handoff_waggle_app/design-files/screens/auth.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Sign in</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 11px; border-radius: 7px; transition: .14s; white-space:nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.split { flex:1; min-height:0; display:grid; grid-template-columns: 1.05fr 1fr; }
|
||||
/* brand panel */
|
||||
.brandside { position:relative; overflow:hidden; padding: 56px; display:flex; flex-direction:column; justify-content:space-between; background: linear-gradient(160deg, var(--bg-2), var(--bg)); border-right:1px solid var(--line-soft); }
|
||||
.brandside .comb { position:absolute; inset:0; opacity:.6; pointer-events:none; mask-image: radial-gradient(90% 80% at 30% 30%, black, transparent 75%); }
|
||||
.brandside .bk { position:relative; display:flex; align-items:center; gap:12px; }
|
||||
.brandside .bk .mk { width:34px; height:38px; display:grid; place-items:center; font-weight:800; font-size:16px; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); box-shadow:var(--honey-glow); }
|
||||
.brandside .bk b { font-size:19px; font-weight:700; letter-spacing:-0.01em; }
|
||||
.brandside .pitch { position:relative; }
|
||||
.brandside .pitch h2 { font-size: clamp(26px,3vw,38px); font-weight:600; letter-spacing:-0.025em; line-height:1.08; margin:0 0 16px; max-width:16ch; }
|
||||
.brandside .pitch h2 em { font-style:normal; color:var(--honey); }
|
||||
.brandside .pitch p { font-size:15px; color:var(--text-2); line-height:1.55; max-width:42ch; margin:0; }
|
||||
.brandside .trust { position:relative; display:flex; flex-direction:column; gap:11px; }
|
||||
.brandside .trust .t { display:flex; align-items:center; gap:11px; font-size:13.5px; color:var(--text-2); }
|
||||
.brandside .trust .t svg { width:17px; height:17px; stroke:var(--honey); fill:none; stroke-width:1.8; flex:none; }
|
||||
|
||||
/* form panel */
|
||||
.formside { display:flex; align-items:center; justify-content:center; padding: 40px 32px; overflow:auto; }
|
||||
.formcard { width:100%; max-width: 380px; }
|
||||
.fhead { text-align:center; margin-bottom: 26px; }
|
||||
.fhead h1 { font-size: 24px; font-weight:650; letter-spacing:-0.02em; margin:0 0 6px; }
|
||||
.fhead p { font-size:13.5px; color:var(--text-muted); margin:0; }
|
||||
.fhead p a { color:var(--honey); text-decoration:none; font-weight:600; cursor:pointer; }
|
||||
|
||||
.sso { display:grid; gap:9px; margin-bottom:18px; }
|
||||
.ssobtn { display:flex; align-items:center; justify-content:center; gap:10px; padding:11px; border-radius:11px; border:1px solid var(--line-strong); background:var(--surface); color:var(--text); font-family:var(--sans); font-size:14px; font-weight:600; cursor:pointer; transition:.14s; }
|
||||
.ssobtn:hover { border-color:var(--honey-line); background:var(--surface-2); }
|
||||
.ssobtn .g { width:18px; height:18px; border-radius:4px; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:700; background:var(--surface-3); flex:none; }
|
||||
.divider { display:flex; align-items:center; gap:12px; margin:18px 0; color:var(--text-dim); font-size:12px; font-family:var(--mono); }
|
||||
.divider::before, .divider::after { content:''; flex:1; height:1px; background:var(--line-soft); }
|
||||
|
||||
.fld { margin-bottom:13px; }
|
||||
.fld label { display:block; font-size:12.5px; font-weight:600; color:var(--text-2); margin-bottom:6px; }
|
||||
.fld input { width:100%; padding:11px 14px; border-radius:11px; border:1px solid var(--line); background:var(--surface); color:var(--text); font-family:var(--sans); font-size:14.5px; outline:none; transition:.14s; }
|
||||
.fld input:focus { border-color:var(--honey-line); box-shadow:var(--honey-glow); }
|
||||
.fld .lrow { display:flex; align-items:center; justify-content:space-between; }
|
||||
.fld .lrow a { font-size:11.5px; color:var(--honey); text-decoration:none; cursor:pointer; }
|
||||
.submit { width:100%; padding:12px; border-radius:11px; border:0; background:var(--honey); color:#1a1407; font-family:var(--sans); font-size:15px; font-weight:650; cursor:pointer; transition:.14s; margin-top:6px; }
|
||||
.submit:hover { background:var(--honey-bright); }
|
||||
.fineprint { text-align:center; font-size:11.5px; color:var(--text-dim); margin-top:16px; line-height:1.5; } .fineprint a { color:var(--text-2); }
|
||||
|
||||
/* OTP */
|
||||
.otp { display:flex; gap:10px; justify-content:center; margin:8px 0 4px; }
|
||||
.otp input { width:48px; height:56px; text-align:center; font-family:var(--mono); font-size:22px; border-radius:12px; border:1px solid var(--line); background:var(--surface); color:var(--text); outline:none; }
|
||||
.otp input:focus { border-color:var(--honey-line); box-shadow:var(--honey-glow); }
|
||||
.otp input.filled { border-color:var(--honey-line); color:var(--honey); }
|
||||
.resend { text-align:center; font-size:12.5px; color:var(--text-muted); margin-top:14px; } .resend a { color:var(--honey); cursor:pointer; }
|
||||
|
||||
/* local-first banner */
|
||||
.localnote { display:flex; gap:10px; align-items:flex-start; padding:12px 14px; border-radius:11px; background:var(--honey-wash); border:1px solid var(--honey-line); margin-bottom:20px; }
|
||||
.localnote svg { width:16px; height:16px; stroke:var(--honey); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.localnote p { margin:0; font-size:12px; color:var(--text-2); line-height:1.5; } .localnote b { color:var(--text); }
|
||||
|
||||
.view { display:none; } .view.on { display:block; }
|
||||
@media (max-width: 820px){ .split { grid-template-columns:1fr; } .brandside { display:none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Auth · Clerk · state</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="signin">Sign in</button>
|
||||
<button data-v="signup">Sign up</button>
|
||||
<button data-v="verify">Verify</button>
|
||||
<button data-v="sso">SSO</button>
|
||||
</div>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="split">
|
||||
<div class="brandside">
|
||||
<div class="comb"></div>
|
||||
<div class="bk"><div class="mk hex">W</div><b>Waggle</b></div>
|
||||
<div class="pitch">
|
||||
<h2>Your work follows you, <em>everywhere.</em></h2>
|
||||
<p>Sign in to sync your hive across devices, collaborate with a team, and pick up any project exactly where you left off — on any machine.</p>
|
||||
</div>
|
||||
<div class="trust">
|
||||
<div class="t"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>An account is optional — Waggle runs fully local without one</div>
|
||||
<div class="t"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg>Your memory stays yours; sign-in only adds sync</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="formside">
|
||||
<div class="formcard">
|
||||
<!-- SIGN IN -->
|
||||
<div class="view on" data-view="signin">
|
||||
<div class="fhead"><h1>Welcome back</h1><p>New to Waggle? <a data-go="signup">Create an account</a></p></div>
|
||||
<div class="sso">
|
||||
<button class="ssobtn"><span class="g">G</span>Continue with Google</button>
|
||||
<button class="ssobtn"><span class="g">⌥</span>Continue with Apple</button>
|
||||
</div>
|
||||
<div class="divider">or</div>
|
||||
<div class="fld"><label>Email</label><input type="email" value="mara@egzakta.com"></div>
|
||||
<div class="fld"><div class="lrow"><label>Password</label><a data-go="verify">Forgot?</a></div><input type="password" value="••••••••••"></div>
|
||||
<button class="submit" data-go="home">Sign in</button>
|
||||
<div class="fineprint">By continuing you agree to the <a href="#">Terms</a> & <a href="#">Privacy Policy</a>.</div>
|
||||
</div>
|
||||
|
||||
<!-- SIGN UP -->
|
||||
<div class="view" data-view="signup">
|
||||
<div class="fhead"><h1>Create your hive</h1><p>Already have an account? <a data-go="signin">Sign in</a></p></div>
|
||||
<div class="localnote"><svg viewBox="0 0 24 24"><path d="M3 11l9-8 9 8M5 10v10h14V10"/></svg><p><b>You don't need this to start.</b> Waggle works locally right away — create an account only when you want sync or a team.</p></div>
|
||||
<div class="sso">
|
||||
<button class="ssobtn"><span class="g">G</span>Sign up with Google</button>
|
||||
</div>
|
||||
<div class="divider">or</div>
|
||||
<div class="fld"><label>Name</label><input value="Mara Kovač"></div>
|
||||
<div class="fld"><label>Email</label><input type="email" placeholder="you@company.com"></div>
|
||||
<div class="fld"><label>Password</label><input type="password" placeholder="At least 10 characters"></div>
|
||||
<button class="submit" data-go="verify">Create account</button>
|
||||
<div class="fineprint">We'll send a code to verify your email.</div>
|
||||
</div>
|
||||
|
||||
<!-- VERIFY (OTP) -->
|
||||
<div class="view" data-view="verify">
|
||||
<div class="fhead"><h1>Check your email</h1><p>We sent a 6-digit code to <b style="color:var(--text-2)">mara@egzakta.com</b></p></div>
|
||||
<div class="otp" id="otp"></div>
|
||||
<button class="submit" data-go="home" style="margin-top:18px">Verify & continue</button>
|
||||
<div class="resend">Didn't get it? <a>Resend code</a> · <a data-go="signin">Use a different email</a></div>
|
||||
</div>
|
||||
|
||||
<!-- SSO / ORG -->
|
||||
<div class="view" data-view="sso">
|
||||
<div class="fhead"><h1>Single sign-on</h1><p>Use your organization's identity provider.</p></div>
|
||||
<div class="fld"><label>Work email or organization</label><input placeholder="you@company.com"></div>
|
||||
<button class="submit" data-go="home">Continue with SSO</button>
|
||||
<div class="divider">enterprise</div>
|
||||
<div class="localnote" style="background:var(--bg-2);border-color:var(--line-soft)"><svg viewBox="0 0 24 24" style="stroke:var(--text-muted)"><path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg><p>SAML, SCIM provisioning, and audit logs are available on <b>Teams</b> and <b>KVARK</b>. <a style="color:var(--honey)" href="#">Talk to sales →</a></p></div>
|
||||
<div class="fineprint"><a data-go="signin">← Back to sign in</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
// OTP boxes
|
||||
document.getElementById('otp').innerHTML = Array.from({length:6},(_, i)=>`<input maxlength="1" inputmode="numeric" data-i="${i}" value="${i<3?[2,4,9][i]:''}">`).join('');
|
||||
document.querySelectorAll('#otp input').forEach((inp,i,arr)=>{
|
||||
if(inp.value) inp.classList.add('filled');
|
||||
inp.addEventListener('input', e=>{ inp.classList.toggle('filled', !!inp.value); if(inp.value && arr[i+1]) arr[i+1].focus(); });
|
||||
inp.addEventListener('keydown', e=>{ if(e.key==='Backspace' && !inp.value && arr[i-1]) arr[i-1].focus(); });
|
||||
});
|
||||
|
||||
function go(v){
|
||||
if(v==='home'){ document.body.style.transition='opacity .25s'; document.body.style.opacity='.4'; setTimeout(()=>{ try{ location.href='../Waggle Reimagined.html#home'; }catch(e){} }, 260); return; }
|
||||
document.querySelectorAll('.view').forEach(el=>el.classList.toggle('on', el.dataset.view===v));
|
||||
document.querySelectorAll('#seg button').forEach(b=>b.classList.toggle('on', b.dataset.v===v));
|
||||
}
|
||||
document.getElementById('seg').addEventListener('click', e=>{ const b=e.target.closest('button'); if(b) go(b.dataset.v); });
|
||||
document.addEventListener('click', e=>{ const a=e.target.closest('[data-go]'); if(a){ e.preventDefault(); go(a.dataset.go); } });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,195 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Benchmarks</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
|
||||
.controls { flex:none; display:flex; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line-soft); background:color-mix(in srgb,var(--bg) 88%,transparent); backdrop-filter:blur(10px); z-index:30; }
|
||||
.controls .lab { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); }
|
||||
.seg { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.seg button { font-family:var(--sans); font-size:12.5px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:6px 13px; border-radius:7px; transition:.14s; white-space:nowrap; }
|
||||
.seg button.on { background:var(--honey); color:#1a1407; }
|
||||
.controls .vlabel { font-size:12.5px; color:var(--text-muted); } .controls .vlabel b { color:var(--text); font-weight:600; }
|
||||
.controls .right { margin-left:auto; display:flex; align-items:center; gap:10px; }
|
||||
.tbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--surface); color:var(--text-2); cursor:pointer; }
|
||||
.tbtn:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.stage { flex:1; min-height:0; overflow:auto; }
|
||||
.wrap { max-width:1000px; margin:0 auto; padding:30px 32px 70px; }
|
||||
.view { display:none; } .view.on { display:block; }
|
||||
|
||||
.head { margin-bottom:24px; }
|
||||
.head .eyebrow { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--honey); margin-bottom:12px; display:flex; align-items:center; gap:9px; } .head .eyebrow::before { content:''; width:20px; height:1px; background:var(--honey-line); }
|
||||
.head h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 10px; } .head h1 em { font-style:normal; color:var(--honey); }
|
||||
.head p { font-size:15px; color:var(--text-muted); line-height:1.55; margin:0; max-width:64ch; } .head p b { color:var(--text-2); }
|
||||
|
||||
/* category framing */
|
||||
.frame-cats { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:30px; }
|
||||
.fcat { padding:22px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); }
|
||||
.fcat.us { border-color:var(--honey-line); background:linear-gradient(155deg,var(--surface-2),var(--surface)); }
|
||||
.fcat .tag { font-family:var(--mono); font-size:10px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-dim); margin-bottom:10px; } .fcat.us .tag { color:var(--honey); }
|
||||
.fcat h3 { font-size:18px; font-weight:650; letter-spacing:-0.01em; margin:0 0 8px; }
|
||||
.fcat p { margin:0; font-size:13px; color:var(--text-muted); line-height:1.55; }
|
||||
.fcat .who { margin-top:12px; font-size:11.5px; color:var(--text-dim); } .fcat .who b { color:var(--text-2); }
|
||||
|
||||
/* matrix */
|
||||
.matrix { border:1px solid var(--line-soft); border-radius:var(--r-lg); overflow:hidden; background:var(--surface); }
|
||||
.mtable { width:100%; border-collapse:collapse; }
|
||||
.mtable th, .mtable td { padding:13px 10px; text-align:center; border-bottom:1px solid var(--line-soft); }
|
||||
.mtable thead th { font-size:11.5px; font-weight:650; color:var(--text-2); position:sticky; top:0; background:var(--surface-2); }
|
||||
.mtable thead th.usCol { color:var(--honey); }
|
||||
.mtable th.cap { text-align:left; font-size:13px; font-weight:600; color:var(--text); width:32%; }
|
||||
.mtable td.cap { text-align:left; font-size:13px; color:var(--text-2); width:32%; }
|
||||
.mtable .usCol { background:color-mix(in srgb,var(--honey) 7%,transparent); }
|
||||
.mtable td.usCol { border-left:1px solid var(--honey-line); border-right:1px solid var(--honey-line); }
|
||||
.mtable tbody tr:last-child td.usCol { border-bottom:1px solid var(--honey-line); }
|
||||
.mk { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:999px; font-size:13px; }
|
||||
.mk.yes { color:var(--healthy); } .mk.us { color:var(--honey); font-weight:700; }
|
||||
.mk.part { color:var(--attention); } .mk.no { color:var(--text-dim); }
|
||||
.colsub { font-size:9.5px; font-weight:400; color:var(--text-dim); display:block; margin-top:2px; font-family:var(--mono); }
|
||||
.legend { display:flex; gap:18px; flex-wrap:wrap; margin-top:16px; font-size:12.5px; color:var(--text-muted); }
|
||||
.legend span { display:inline-flex; align-items:center; gap:7px; }
|
||||
.disclaimer { margin-top:18px; display:flex; gap:11px; align-items:flex-start; padding:14px 16px; border-radius:var(--r); background:var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.disclaimer svg { width:16px; height:16px; stroke:var(--text-muted); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.disclaimer p { margin:0; font-size:12px; color:var(--text-dim); line-height:1.55; } .disclaimer b { color:var(--text-2); }
|
||||
|
||||
/* memory bench */
|
||||
.bench { display:grid; gap:12px; margin-top:8px; }
|
||||
.barrow { display:grid; grid-template-columns:180px 1fr 64px; gap:16px; align-items:center; }
|
||||
.barrow .blab { font-size:13.5px; font-weight:600; text-align:right; line-height:1.15; } .barrow .blab small { display:block; font-weight:400; color:var(--text-dim); font-size:10.5px; font-family:var(--mono); margin-top:2px; }
|
||||
.barrow .track { height:34px; border-radius:9px; background:var(--surface); border:1px solid var(--line-soft); overflow:hidden; }
|
||||
.barrow .fill { height:100%; border-radius:8px 0 0 8px; background:var(--surface-3); }
|
||||
.barrow.us .fill { background:linear-gradient(90deg,var(--honey-deep),var(--honey-bright)); box-shadow:var(--honey-glow); }
|
||||
.barrow .bval { font-family:var(--mono); font-size:14px; font-weight:600; color:var(--text-2); } .barrow.us .bval { color:var(--honey); }
|
||||
.benchstats { display:grid; grid-template-columns:repeat(3,1fr); gap:14px; margin:26px 0; }
|
||||
.bs { padding:20px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); } .bs .v { font-size:32px; font-weight:750; letter-spacing:-0.03em; color:var(--honey); } .bs .l { font-size:13px; color:var(--text-muted); margin-top:6px; } .bs .l b { color:var(--text); }
|
||||
|
||||
@media (max-width:820px){ .frame-cats { grid-template-columns:1fr; } .mtable thead th, .mtable td { padding:10px 5px; font-size:10px; } .barrow { grid-template-columns:110px 1fr 50px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Benchmarks · view</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="caps">vs competitors</button>
|
||||
<button data-v="memory">Memory SOTA</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Capabilities</b> — where Waggle sits vs the field</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- CAPS -->
|
||||
<div class="view on wrap" data-view="caps">
|
||||
<div class="head">
|
||||
<div class="eyebrow">How we're different</div>
|
||||
<h1>They automate tasks. <em>Waggle remembers you.</em></h1>
|
||||
<p>The strong agents today are <b>terminal coding tools</b> for engineers. Waggle plays a different game: a <b>persistent, local-first memory layer</b> for knowledge workers that even <b>runs those agents inside it</b>. Here's the honest lay of the land.</p>
|
||||
</div>
|
||||
|
||||
<div class="frame-cats">
|
||||
<div class="fcat">
|
||||
<div class="tag">The field</div>
|
||||
<h3>Task agents</h3>
|
||||
<p>Powerful, mostly terminal-based, model-locked, and built for developers. Each session starts fresh; the intelligence lives in the model, not in a memory of you.</p>
|
||||
<div class="who"><b>Claude Code · Codex · Claude Cowork · Hermes · Odysseus</b></div>
|
||||
</div>
|
||||
<div class="fcat us">
|
||||
<div class="tag">Our category</div>
|
||||
<h3>A memory layer + workspace</h3>
|
||||
<p>Knows you and your work across every session, runs on any model (even local), is built for non-technical experts — and can launch the task agents into its shared memory.</p>
|
||||
<div class="who"><b>Waggle</b> — complements them, doesn't compete head-on</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="matrix">
|
||||
<table class="mtable">
|
||||
<thead><tr>
|
||||
<th class="cap">Capability</th>
|
||||
<th class="usCol">Waggle</th>
|
||||
<th>Claude Code<span class="colsub">CLI</span></th>
|
||||
<th>Codex<span class="colsub">CLI</span></th>
|
||||
<th>Cowork<span class="colsub">Anthropic</span></th>
|
||||
<th>Hermes<span class="colsub">agent</span></th>
|
||||
<th>Odysseus<span class="colsub">agent</span></th>
|
||||
</tr></thead>
|
||||
<tbody id="mbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span><span class="mk yes">●</span>Yes</span>
|
||||
<span><span class="mk part">◐</span>Partial / limited</span>
|
||||
<span><span class="mk no">○</span>No / not the focus</span>
|
||||
</div>
|
||||
<div class="disclaimer">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 8h.01M11 12h1v4h1"/></svg>
|
||||
<p><b>This is a positioning view, not a lab benchmark</b> — capabilities as understood June 2026, focused on the dimensions Waggle is built around. Coding agents are genuinely excellent at deep code work (the last row), which is exactly why Waggle <b>launches them</b> rather than replacing them. The one head-to-head lab result is the memory benchmark → see "Memory SOTA".</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MEMORY -->
|
||||
<div class="view wrap" data-view="memory">
|
||||
<div class="head">
|
||||
<div class="eyebrow">State of the art · LoCoMo · June 2026</div>
|
||||
<h1>The best long-term memory <em>on record.</em></h1>
|
||||
<p>On <b>LoCoMo</b> — the standard test for long-term conversational memory — Waggle's open-source substrate scores <b>87.66%</b>, a new state of the art, measured under the prior leader's own protocol and judge.</p>
|
||||
</div>
|
||||
<div class="bench">
|
||||
<div class="barrow us"><div class="blab">Waggle · Hive Mind<small>ours · local</small></div><div class="track"><div class="fill" style="width:87.7%"></div></div><div class="bval">87.66</div></div>
|
||||
<div class="barrow"><div class="blab">Memori<small>prev. SOTA</small></div><div class="track"><div class="fill" style="width:81.95%"></div></div><div class="bval">81.95</div></div>
|
||||
<div class="barrow"><div class="blab">LangMem<small>corrected</small></div><div class="track"><div class="fill" style="width:78.05%"></div></div><div class="bval">78.05</div></div>
|
||||
<div class="barrow"><div class="blab">Mem0<small>baseline</small></div><div class="track"><div class="fill" style="width:62.47%"></div></div><div class="bval">62.47</div></div>
|
||||
</div>
|
||||
<div class="benchstats">
|
||||
<div class="bs"><div class="v">+5.71</div><div class="l">points over the prior best · <b>z = 4.42, p < 10⁻⁵</b></div></div>
|
||||
<div class="bs"><div class="v">92.75%</div><div class="l">single-hop recall — <b>~1pt off the full-context ceiling</b></div></div>
|
||||
<div class="bs"><div class="v">100%</div><div class="l">local — warm recalls in <b>58–83 ms</b>, on-device</div></div>
|
||||
</div>
|
||||
<div class="disclaimer">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 8h.01M11 12h1v4h1"/></svg>
|
||||
<p><b>LoCoMo</b>, N = 1,540, GPT-4.1-mini as answerer & judge — the prior SOTA's exact published protocol, reproduced in-harness to 0.03 points before comparison. The intelligence lives in the <b>memory layer, not the model</b>, so it travels onto a small local model too. Honest caveat: higher token use per question than the leanest systems; efficiency work underway. Reproducible offline: <span style="font-family:var(--mono);color:var(--text-2)">github.com/marolinik/hive-mind</span>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
// matrix data — Y=yes, P=partial, N=no. Order: Waggle, ClaudeCode, Codex, Cowork, Hermes, Odysseus
|
||||
const CAPS = [
|
||||
['Persistent memory across sessions', ['Y','P','N','P','P','P']],
|
||||
['Local-first & private by default', ['Y','N','N','N','P','P']],
|
||||
['Any model — incl. small local models', ['Y','N','N','N','P','P']],
|
||||
['Built for non-technical experts', ['Y','N','N','P','N','N']],
|
||||
['Runs your existing coding agents', ['Y','N','N','N','N','N']],
|
||||
['Self-evolving skills', ['Y','N','N','N','P','N']],
|
||||
['Skills shared across agents/workspaces', ['Y','P','P','N','P','N']],
|
||||
['Multi-agent swarm', ['Y','P','N','P','P','Y']],
|
||||
['Native desktop app · Win + Mac', ['Y','N','N','P','N','N']],
|
||||
['Audit-ready / EU AI Act', ['Y','P','P','P','N','N']],
|
||||
['Deep coding in the terminal', ['P','Y','Y','P','P','Y']],
|
||||
];
|
||||
const MK = { Y:'<span class="mk yes">●</span>', P:'<span class="mk part">◐</span>', N:'<span class="mk no">○</span>' };
|
||||
const USMK = '<span class="mk us">●</span>';
|
||||
document.getElementById('mbody').innerHTML = CAPS.map(([cap, marks]) => `
|
||||
<tr>
|
||||
<td class="cap">${cap}</td>
|
||||
<td class="usCol">${marks[0]==='Y'?USMK:(marks[0]==='P'?'<span class="mk part">◐</span>':'<span class="mk no">○</span>')}</td>
|
||||
${marks.slice(1).map(m=>`<td>${MK[m]}</td>`).join('')}
|
||||
</tr>`).join('');
|
||||
|
||||
const labels = { caps:'<b>Capabilities</b> — where Waggle sits vs the field', memory:'<b>Memory SOTA</b> — the one head-to-head lab result' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e=>{ const b=e.target.closest('button'); if(!b) return; [...seg.children].forEach(x=>x.classList.toggle('on',x===b)); document.querySelectorAll('.view').forEach(v=>v.classList.toggle('on', v.dataset.view===b.dataset.v)); document.getElementById('vlabel').innerHTML = labels[b.dataset.v]; document.querySelector('.stage').scrollTop=0; });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
247
docs/design_handoff_waggle_app/design-files/screens/billing.html
Normal file
@@ -0,0 +1,247 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Billing</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 11px; border-radius: 7px; transition: .14s; white-space:nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.stage { flex:1; min-height:0; overflow:auto; }
|
||||
.view { display:none; } .view.on { display:block; }
|
||||
.view[data-view="checkout"].on { display:grid; }
|
||||
|
||||
/* PLANS */
|
||||
.wrap { max-width: 980px; margin: 0 auto; padding: 34px 32px 60px; }
|
||||
.phead { text-align:center; margin-bottom: 22px; }
|
||||
.phead h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 8px; } .phead h1 em { font-style:normal; color:var(--honey); }
|
||||
.phead p { font-size:14.5px; color:var(--text-muted); margin:0 0 18px; }
|
||||
.cycle { display:inline-flex; padding:4px; gap:3px; border-radius:11px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.cycle button { font-family:var(--sans); font-size:13px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:8px 16px; border-radius:8px; }
|
||||
.cycle button.on { background:var(--honey); color:#1a1407; }
|
||||
.cycle .save { font-size:10.5px; color:var(--healthy); margin-left:5px; }
|
||||
.cycle button.on .save { color:#1a1407; }
|
||||
|
||||
.plans { display:grid; grid-template-columns:repeat(3,1fr); gap:16px; margin-top:24px; align-items:stretch; }
|
||||
.plan { padding:26px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); display:flex; flex-direction:column; position:relative; }
|
||||
.plan.feat { border-color:var(--honey-line); box-shadow:var(--honey-glow); }
|
||||
.plan.cur { border-color:var(--work); }
|
||||
.plan .pop { position:absolute; top:-11px; left:26px; font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:#1a1407; background:var(--honey); padding:4px 11px; border-radius:999px; }
|
||||
.plan .curtag { position:absolute; top:-11px; right:26px; font-size:11px; font-weight:700; text-transform:uppercase; color:#fff; background:var(--work); padding:4px 11px; border-radius:999px; }
|
||||
.plan .pn { font-size:15px; font-weight:600; color:var(--text-2); }
|
||||
.plan .pp { font-size:38px; font-weight:750; letter-spacing:-0.03em; margin:12px 0 2px; } .plan .pp small { font-size:15px; font-weight:500; color:var(--text-muted); letter-spacing:0; }
|
||||
.plan .ptag { font-size:13px; color:var(--text-muted); margin-bottom:20px; min-height:36px; }
|
||||
.plan ul { list-style:none; margin:0 0 24px; padding:0; display:grid; gap:10px; flex:1; }
|
||||
.plan li { font-size:13px; color:var(--text-2); display:grid; grid-template-columns:17px 1fr; gap:9px; line-height:1.4; }
|
||||
.plan li svg { width:14px; height:14px; stroke:var(--healthy); fill:none; stroke-width:2.4; margin-top:2px; }
|
||||
.pbtn { padding:11px; border-radius:10px; font-family:var(--sans); font-size:14px; font-weight:650; cursor:pointer; border:1px solid transparent; text-align:center; }
|
||||
.pbtn.go { background:var(--honey); color:#1a1407; } .pbtn.go:hover { background:var(--honey-bright); }
|
||||
.pbtn.ghost { background:var(--surface-2); color:var(--text-2); border-color:var(--line-strong); } .pbtn.ghost:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.pbtn.disabled { background:transparent; color:var(--text-dim); border-color:var(--line-soft); cursor:default; }
|
||||
|
||||
/* CHECKOUT */
|
||||
.cowrap { max-width: 860px; margin:0 auto; padding: 30px 32px 60px; display:grid; grid-template-columns: 1.2fr 1fr; gap:28px; }
|
||||
.panel { border:1px solid var(--line-soft); background:var(--surface); border-radius:var(--r-lg); padding:24px; }
|
||||
.panel h2 { font-size:16px; font-weight:650; margin:0 0 18px; letter-spacing:-0.01em; }
|
||||
.fld { margin-bottom:14px; } .fld label { display:block; font-size:12.5px; font-weight:600; color:var(--text-2); margin-bottom:6px; }
|
||||
.fld input { width:100%; padding:11px 14px; border-radius:10px; border:1px solid var(--line); background:var(--bg-2); color:var(--text); font-family:var(--sans); font-size:14px; outline:none; }
|
||||
.fld input:focus { border-color:var(--honey-line); box-shadow:var(--honey-glow); }
|
||||
.cardfield { position:relative; }
|
||||
.cardfield .brand { position:absolute; right:12px; top:50%; transform:translateY(-50%); font-family:var(--mono); font-size:11px; color:var(--text-dim); }
|
||||
.frow { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
|
||||
.secure { display:flex; align-items:center; gap:8px; font-size:11.5px; color:var(--text-dim); margin-top:6px; }
|
||||
.secure svg { width:13px; height:13px; stroke:var(--healthy); fill:none; stroke-width:1.8; }
|
||||
.secure b { color:var(--text-2); font-weight:500; }
|
||||
.powered { text-align:center; font-family:var(--mono); font-size:11px; color:var(--text-dim); margin-top:16px; }
|
||||
.powered b { color:var(--text-2); }
|
||||
|
||||
/* summary */
|
||||
.summary .line { display:flex; align-items:center; justify-content:space-between; padding:11px 0; border-bottom:1px solid var(--line-soft); font-size:13.5px; }
|
||||
.summary .line .l { color:var(--text-muted); } .summary .line .v { font-weight:600; }
|
||||
.summary .line.total { border-bottom:0; padding-top:16px; font-size:16px; } .summary .line.total .v { color:var(--honey); font-weight:750; font-size:20px; letter-spacing:-0.02em; }
|
||||
.summary .planrow { display:flex; align-items:center; gap:12px; padding-bottom:16px; border-bottom:1px solid var(--line-soft); margin-bottom:6px; }
|
||||
.summary .planrow .wm { width:34px; height:38px; flex:none; display:grid; place-items:center; font-weight:800; font-size:13px; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.summary .planrow b { font-size:15px; font-weight:650; display:block; } .summary .planrow span { font-size:12px; color:var(--text-muted); display:block; margin-top:2px; }
|
||||
.promo { display:flex; gap:8px; margin:14px 0; } .promo input { flex:1; padding:9px 12px; border-radius:9px; border:1px solid var(--line); background:var(--bg-2); color:var(--text); font-family:var(--sans); font-size:13px; outline:none; }
|
||||
.promo button { padding:9px 14px; border-radius:9px; border:1px solid var(--line-strong); background:var(--surface-2); color:var(--text-2); font-size:12.5px; font-weight:600; cursor:pointer; }
|
||||
.paybtn { width:100%; padding:13px; border-radius:11px; border:0; background:var(--honey); color:#1a1407; font-family:var(--sans); font-size:15px; font-weight:650; cursor:pointer; margin-top:14px; }
|
||||
.paybtn:hover { background:var(--honey-bright); }
|
||||
.guarantee { text-align:center; font-size:11.5px; color:var(--text-dim); margin-top:12px; }
|
||||
|
||||
/* SUCCESS */
|
||||
.succ { max-width:520px; margin:0 auto; padding:70px 32px; text-align:center; }
|
||||
.succ .ring { width:78px; height:78px; border-radius:999px; margin:0 auto 24px; display:grid; place-items:center; background:var(--healthy-wash); border:1px solid color-mix(in srgb,var(--healthy) 40%,transparent); }
|
||||
.succ .ring svg { width:36px; height:36px; stroke:var(--healthy); fill:none; stroke-width:2.2; }
|
||||
.succ h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 12px; } .succ h1 em { font-style:normal; color:var(--honey); }
|
||||
.succ p { font-size:15px; color:var(--text-2); line-height:1.55; margin:0 auto 28px; max-width:42ch; } .succ p b { color:var(--text); }
|
||||
.succ .rcpt { text-align:left; border:1px solid var(--line-soft); border-radius:var(--r); background:var(--surface); padding:16px 18px; margin-bottom:24px; }
|
||||
.succ .rcpt .r { display:flex; justify-content:space-between; padding:7px 0; font-size:13px; } .succ .rcpt .r .l { color:var(--text-muted); } .succ .rcpt .r .v { font-weight:600; }
|
||||
.succ .cta { display:inline-flex; gap:10px; }
|
||||
.succ .cta a { padding:12px 22px; border-radius:11px; font-size:14.5px; font-weight:650; text-decoration:none; cursor:pointer; }
|
||||
.succ .cta .go { background:var(--honey); color:#1a1407; } .succ .cta .ghost { background:var(--surface); color:var(--text-2); border:1px solid var(--line-strong); }
|
||||
|
||||
/* MANAGE */
|
||||
.mwrap { max-width:760px; margin:0 auto; padding:30px 32px 60px; }
|
||||
.mwrap h1 { font-size:24px; font-weight:650; letter-spacing:-0.02em; margin:0 0 20px; }
|
||||
.mcard { border:1px solid var(--line-soft); background:var(--surface); border-radius:var(--r-lg); padding:22px; margin-bottom:14px; }
|
||||
.mcard.cur { border-color:var(--honey-line); }
|
||||
.mtop { display:flex; align-items:center; justify-content:space-between; gap:14px; }
|
||||
.mtop .pl b { font-size:17px; font-weight:650; } .mtop .pl span { font-size:13px; color:var(--text-muted); display:block; margin-top:3px; }
|
||||
.mtop .badge { font-size:11.5px; font-weight:650; color:var(--honey); background:var(--honey-wash); border:1px solid var(--honey-line); padding:6px 12px; border-radius:999px; }
|
||||
.mrow { display:flex; align-items:center; justify-content:space-between; padding:13px 0; border-top:1px solid var(--line-soft); font-size:13.5px; }
|
||||
.mrow .l { color:var(--text-muted); } .mrow .v { font-weight:600; display:flex; align-items:center; gap:9px; }
|
||||
.mrow .card { font-family:var(--mono); font-size:13px; }
|
||||
.mrow .chg { font-size:12px; font-weight:600; color:var(--honey); cursor:pointer; }
|
||||
.invoices .iv { display:grid; grid-template-columns:1fr auto auto auto; gap:14px; align-items:center; padding:11px 0; border-top:1px solid var(--line-soft); font-size:13px; }
|
||||
.invoices .iv:first-child { border-top:0; }
|
||||
.invoices .iv .dt { color:var(--text-2); } .invoices .iv .am { font-family:var(--mono); color:var(--text-2); } .invoices .iv .st { font-size:11px; color:var(--healthy); background:var(--healthy-wash); padding:3px 8px; border-radius:999px; } .invoices .iv .dl { font-size:12px; color:var(--honey); cursor:pointer; }
|
||||
.btn { font-family:var(--sans); font-size:13px; font-weight:650; padding:10px 16px; border-radius:10px; cursor:pointer; border:1px solid transparent; }
|
||||
.btn.ghost { background:var(--surface-2); color:var(--text-2); border-color:var(--line-strong); } .btn.danger { background:transparent; color:var(--risk); border-color:color-mix(in srgb,var(--risk) 35%,transparent); }
|
||||
|
||||
@media (max-width:820px){ .plans { grid-template-columns:1fr; } .cowrap { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Billing · Stripe · state</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="plans">Plans</button>
|
||||
<button data-v="checkout">Checkout</button>
|
||||
<button data-v="success">Success</button>
|
||||
<button data-v="manage">Manage</button>
|
||||
</div>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- PLANS -->
|
||||
<div class="view on wrap" data-view="plans">
|
||||
<div class="phead">
|
||||
<h1>Upgrade your <em>hive.</em></h1>
|
||||
<p>Memory is free forever. You only pay for scale — no feature-count games.</p>
|
||||
<div class="cycle" id="cycle"><button class="on" data-c="mo">Monthly</button><button data-c="yr">Annual<span class="save">−20%</span></button></div>
|
||||
</div>
|
||||
<div class="plans">
|
||||
<div class="plan cur">
|
||||
<span class="curtag">Current</span>
|
||||
<div class="pn">Solo</div>
|
||||
<div class="pp">$0<small> / forever</small></div>
|
||||
<div class="ptag">For individuals exploring an AI workspace.</div>
|
||||
<ul><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Personal memory graph</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>All major LLMs + local</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Local-first by default</li></ul>
|
||||
<div class="pbtn disabled">Your plan</div>
|
||||
</div>
|
||||
<div class="plan feat">
|
||||
<span class="pop">Most popular</span>
|
||||
<div class="pn">Pro</div>
|
||||
<div class="pp" data-mo="$19" data-yr="$15">$19<small> / month</small></div>
|
||||
<div class="ptag">For power users compounding across projects.</div>
|
||||
<ul><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Everything in Solo</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Sync across devices</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Marketplace skills & connectors</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Self-evolving skills</li></ul>
|
||||
<div class="pbtn go" data-go="checkout">Choose Pro</div>
|
||||
</div>
|
||||
<div class="plan">
|
||||
<div class="pn">Teams</div>
|
||||
<div class="pp" data-mo="$49" data-yr="$39">$49<small> / seat / mo</small></div>
|
||||
<div class="ptag">Shared memory without losing privacy.</div>
|
||||
<ul><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Everything in Pro</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>Shared team memory</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>WaggleDance multi-agent</li><li><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>SSO & role-based access</li></ul>
|
||||
<div class="pbtn ghost" data-go="checkout">Choose Teams</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CHECKOUT -->
|
||||
<div class="view cowrap" data-view="checkout">
|
||||
<div class="panel">
|
||||
<h2>Payment details</h2>
|
||||
<div class="fld"><label>Email</label><input value="mara@egzakta.com"></div>
|
||||
<div class="fld"><label>Card information</label>
|
||||
<div class="cardfield"><input placeholder="1234 1234 1234 1234" value="4242 4242 4242 4242"><span class="brand">VISA</span></div>
|
||||
</div>
|
||||
<div class="frow"><div class="fld"><input placeholder="MM / YY" value="08 / 28"></div><div class="fld"><input placeholder="CVC" value="•••"></div></div>
|
||||
<div class="fld"><label>Name on card</label><input value="Mara Kovač"></div>
|
||||
<div class="fld"><label>Country</label><input value="Germany"></div>
|
||||
<div class="secure"><svg viewBox="0 0 24 24"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg><b>Encrypted & secure.</b> We never store your card — Stripe does.</div>
|
||||
<button class="paybtn" data-go="success">Pay $19.00 / month</button>
|
||||
<div class="powered">Powered by <b>Stripe</b> · cancel anytime</div>
|
||||
</div>
|
||||
<div class="panel summary">
|
||||
<h2>Order summary</h2>
|
||||
<div class="planrow"><div class="wm hex">W</div><div><b>Waggle Pro</b><span>Monthly · renews Jul 14</span></div></div>
|
||||
<div class="line"><span class="l">Pro plan</span><span class="v">$19.00</span></div>
|
||||
<div class="promo"><input placeholder="Promo code"><button>Apply</button></div>
|
||||
<div class="line"><span class="l">Tax (est.)</span><span class="v">$0.00</span></div>
|
||||
<div class="line total"><span class="l">Due today</span><span class="v">$19.00</span></div>
|
||||
<div class="guarantee">14-day free trial · you won't be charged until Jun 28</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SUCCESS -->
|
||||
<div class="view succ" data-view="success">
|
||||
<div class="ring"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></div>
|
||||
<h1>You're <em>Pro.</em></h1>
|
||||
<p>Your hive just leveled up — <b>sync, the marketplace, and self-evolving skills</b> are live. Your trial runs 14 days; we'll remind you before the first charge.</p>
|
||||
<div class="rcpt">
|
||||
<div class="r"><span class="l">Plan</span><span class="v">Waggle Pro · Monthly</span></div>
|
||||
<div class="r"><span class="l">Trial ends</span><span class="v">Jun 28, 2026</span></div>
|
||||
<div class="r"><span class="l">Then</span><span class="v">$19.00 / month</span></div>
|
||||
<div class="r"><span class="l">Receipt</span><span class="v" style="color:var(--honey);cursor:pointer">Emailed →</span></div>
|
||||
</div>
|
||||
<div class="cta"><a class="go" data-go="home">Start using Pro →</a><a class="ghost" data-go="manage">Manage billing</a></div>
|
||||
</div>
|
||||
|
||||
<!-- MANAGE -->
|
||||
<div class="view mwrap" data-view="manage">
|
||||
<h1>Billing</h1>
|
||||
<div class="mcard cur">
|
||||
<div class="mtop"><div class="pl"><b>Waggle Pro</b><span>$19.00 / month · renews Jul 14, 2026</span></div><span class="badge">● Active</span></div>
|
||||
<div class="mrow"><span class="l">Billing cycle</span><span class="v">Monthly <span class="chg">Switch to annual (−20%)</span></span></div>
|
||||
<div class="mrow"><span class="l">Payment method</span><span class="v"><span class="card">VISA ···· 4242</span><span class="chg">Update</span></span></div>
|
||||
<div class="mrow"><span class="l">Next charge</span><span class="v">$19.00 on Jul 14</span></div>
|
||||
</div>
|
||||
<div class="mcard invoices">
|
||||
<div class="mtop" style="margin-bottom:8px"><div class="pl"><b style="font-size:14px">Invoices</b></div></div>
|
||||
<div class="iv"><span class="dt">Jun 14, 2026</span><span class="am">$19.00</span><span class="st">Paid</span><span class="dl">PDF ↓</span></div>
|
||||
<div class="iv"><span class="dt">May 14, 2026</span><span class="am">$19.00</span><span class="st">Paid</span><span class="dl">PDF ↓</span></div>
|
||||
<div class="iv"><span class="dt">Apr 14, 2026</span><span class="am">$19.00</span><span class="st">Paid</span><span class="dl">PDF ↓</span></div>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;margin-top:4px"><button class="btn ghost" data-go="plans">Change plan</button><button class="btn danger">Cancel subscription</button></div>
|
||||
<div class="powered" style="text-align:left;margin-top:18px">Subscription managed securely via <b>Stripe</b>.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
function go(v){
|
||||
if(v==='home'){ document.body.style.transition='opacity .25s'; document.body.style.opacity='.4'; setTimeout(()=>{ try{ location.href='../Waggle Reimagined.html#home'; }catch(e){} },260); return; }
|
||||
document.querySelectorAll('.view').forEach(el=>el.classList.toggle('on', el.dataset.view===v));
|
||||
document.querySelectorAll('#seg button').forEach(b=>b.classList.toggle('on', b.dataset.v===v));
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
}
|
||||
document.getElementById('seg').addEventListener('click', e=>{ const b=e.target.closest('button'); if(b) go(b.dataset.v); });
|
||||
document.addEventListener('click', e=>{ const a=e.target.closest('[data-go]'); if(a){ go(a.dataset.go); } });
|
||||
|
||||
// billing cycle toggle
|
||||
document.getElementById('cycle').addEventListener('click', e=>{
|
||||
const b=e.target.closest('button'); if(!b) return;
|
||||
[...e.currentTarget.children].forEach(x=>x.classList.toggle('on',x===b));
|
||||
const c=b.dataset.c;
|
||||
document.querySelectorAll('.pp[data-mo]').forEach(el=>{ const small=el.querySelector('small').outerHTML; el.innerHTML = el.dataset[c] + (c==='yr'? '<small> / mo · billed yearly</small>' : '<small> / month</small>'); if(el.closest('.plan').querySelector('.pn').textContent==='Teams') el.innerHTML = el.dataset[c] + (c==='yr'?'<small> / seat · yearly</small>':'<small> / seat / mo</small>'); });
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
271
docs/design_handoff_waggle_app/design-files/screens/chat.html
Normal file
@@ -0,0 +1,271 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Chat</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
|
||||
/* ── Concept control bar ─────────────────────────────────────── */
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); }
|
||||
.controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
/* ── App frame ───────────────────────────────────────────────── */
|
||||
.app { flex: 1; min-height: 0; display: flex; }
|
||||
.pane { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1; }
|
||||
|
||||
/* context header */
|
||||
.ctx { flex: none; display: flex; align-items: center; gap: 14px; padding: 14px 26px; border-bottom: 1px solid var(--line-soft); }
|
||||
.ctx .wmark { width: 30px; height: 34px; flex: none; display: grid; place-items: center; font-weight: 800; font-size: 13px; color: #1a1407; background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); }
|
||||
.ctx .wname { font-size: 15.5px; font-weight: 650; letter-spacing: -0.01em; }
|
||||
.ctx .wsub { font-size: 12px; color: var(--text-dim); font-family: var(--mono); }
|
||||
.ctx .right { margin-left: auto; display: flex; align-items: center; gap: 9px; }
|
||||
.modelpill { display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 999px; border: 1px solid var(--line); background: var(--surface); font-size: 12.5px; color: var(--text-2); cursor: pointer; transition:.15s; }
|
||||
.modelpill:hover { border-color: var(--honey-line); }
|
||||
.modelpill .dot { background: var(--healthy); }
|
||||
.modelpill b { color: var(--text); font-weight: 600; }
|
||||
.iconbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-muted); cursor: pointer; display: grid; place-items: center; transition:.15s; }
|
||||
.iconbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.iconbtn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 1.8; }
|
||||
|
||||
/* thread */
|
||||
.thread { flex: 1; min-height: 0; overflow: auto; padding: 30px 0; }
|
||||
.thread-inner { max-width: 760px; margin: 0 auto; padding: 0 26px; display: flex; flex-direction: column; gap: 26px; }
|
||||
|
||||
.msg { display: flex; gap: 14px; }
|
||||
.msg .av { width: 30px; height: 34px; flex: none; display: grid; place-items: center; font-size: 12px; font-weight: 700; }
|
||||
.msg.user .av { background: var(--surface-3); color: var(--text-2); border-radius: 9px; }
|
||||
.msg.bot .av { background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); color: #1a1407; }
|
||||
.msg .body { flex: 1; min-width: 0; }
|
||||
.msg .who { font-size: 12px; color: var(--text-dim); margin-bottom: 7px; display: flex; align-items: center; gap: 8px; }
|
||||
.msg .who b { color: var(--text-2); font-weight: 600; }
|
||||
.msg.user .bubble { font-size: 15.5px; line-height: 1.55; color: var(--text); background: var(--surface); border: 1px solid var(--line-soft); padding: 13px 17px; border-radius: 4px 14px 14px 14px; }
|
||||
.msg.bot .prose { font-size: 15.5px; line-height: 1.62; color: var(--text); }
|
||||
.msg.bot .prose p { margin: 0 0 12px; }
|
||||
.msg.bot .prose ul { margin: 0 0 12px; padding-left: 4px; list-style: none; display: grid; gap: 8px; }
|
||||
.msg.bot .prose li { display: grid; grid-template-columns: 16px 1fr; gap: 9px; }
|
||||
.msg.bot .prose li .b { color: var(--honey); }
|
||||
.msg.bot .prose b { font-weight: 650; }
|
||||
|
||||
/* activity stream (the "magic", progressively disclosed) */
|
||||
.activity { margin: 0 0 16px; border: 1px solid var(--line-soft); border-radius: var(--r); overflow: hidden; background: var(--bg-2); }
|
||||
.activity .ahead { display: flex; align-items: center; gap: 10px; padding: 11px 15px; cursor: pointer; user-select: none; }
|
||||
.activity .ahead .spark { width: 18px; height: 18px; flex:none; }
|
||||
.activity .ahead .spark svg { width: 18px; height: 18px; stroke: var(--intel); fill: none; stroke-width: 1.8; }
|
||||
.activity .ahead .t { flex: 1; font-size: 13px; color: var(--text-2); font-weight: 550; }
|
||||
.activity .ahead .t b { color: var(--text); font-weight: 650; }
|
||||
.activity .ahead .chev { color: var(--text-dim); font-size: 12px; transition:.2s; }
|
||||
.activity.open .ahead .chev { transform: rotate(90deg); }
|
||||
.activity .steps { display: none; padding: 4px 15px 14px 15px; flex-direction: column; gap: 0; }
|
||||
.activity.open .steps { display: flex; }
|
||||
.astep { display: flex; align-items: flex-start; gap: 12px; padding: 9px 0; border-top: 1px solid var(--line-soft); position: relative; }
|
||||
.astep .sd { width: 9px; height: 9px; border-radius: 999px; margin-top: 5px; flex: none; }
|
||||
.astep .stext { flex: 1; font-size: 13px; color: var(--text-2); line-height: 1.5; }
|
||||
.astep .stext b { color: var(--text); font-weight: 600; }
|
||||
.astep .stext .mono { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); }
|
||||
.astep .prov { margin-top: 6px; display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 10.5px; color: var(--intel); background: var(--intel-wash); border: 1px solid color-mix(in srgb, var(--intel) 28%, transparent); padding: 3px 9px; border-radius: 7px; }
|
||||
|
||||
/* approval card */
|
||||
.approval { border: 1px solid color-mix(in srgb, var(--attention) 35%, transparent); background: var(--honey-wash); border-radius: var(--r); padding: 16px 18px; }
|
||||
.approval .ah { display: flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 650; }
|
||||
.approval .ah svg { width: 17px; height: 17px; stroke: var(--attention); fill: none; stroke-width: 1.8; }
|
||||
.approval p { margin: 8px 0 14px; font-size: 13px; color: var(--text-muted); line-height: 1.55; }
|
||||
.approval p .mono { font-family: var(--mono); color: var(--text-2); font-size: 12px; }
|
||||
.approval .actions { display: flex; gap: 10px; }
|
||||
.approval .btn { font-family: var(--sans); font-size: 13px; font-weight: 650; padding: 9px 16px; border-radius: 9px; cursor: pointer; border: 1px solid transparent; }
|
||||
.approval .btn.yes { background: var(--honey); color: #1a1407; }
|
||||
.approval .btn.no { background: transparent; border-color: var(--line-strong); color: var(--text-2); }
|
||||
|
||||
/* composer */
|
||||
.composer { flex: none; padding: 16px 26px 20px; border-top: 1px solid var(--line-soft); }
|
||||
.composer-inner { max-width: 760px; margin: 0 auto; }
|
||||
.cbox { border: 1px solid var(--line); background: var(--surface); border-radius: var(--r-lg); padding: 6px 6px 6px 18px; display: flex; align-items: flex-end; gap: 10px; transition:.15s; }
|
||||
.cbox:focus-within { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
|
||||
.cbox textarea { flex: 1; border: 0; background: transparent; resize: none; color: var(--text); font-family: var(--sans); font-size: 15px; line-height: 1.5; outline: none; padding: 9px 0; max-height: 90px; }
|
||||
.cbox textarea::placeholder { color: var(--text-dim); }
|
||||
.cbox .send { width: 40px; height: 40px; flex:none; border-radius: 11px; border: 0; background: var(--honey); color: #1a1407; font-size: 17px; cursor: pointer; display:grid; place-items:center; }
|
||||
.cbox .send:hover { background: var(--honey-bright); }
|
||||
.ctools { display: flex; align-items: center; gap: 8px; margin-top: 11px; padding: 0 2px; }
|
||||
.ctool { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); padding: 6px 10px; border-radius: 8px; border: 1px solid var(--line-soft); background: var(--bg-2); cursor: pointer; transition:.14s; }
|
||||
.ctool:hover { border-color: var(--honey-line); color: var(--text); }
|
||||
.ctool svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 1.9; }
|
||||
.ctools .spacer { flex: 1; }
|
||||
.ctools .hint { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
|
||||
/* right rail / canvas (variation B) */
|
||||
.canvas { flex: none; width: 0; overflow: hidden; border-left: 1px solid var(--line-soft); background: var(--bg-2); display: flex; flex-direction: column; transition: width .25s ease; }
|
||||
body.split .thread-inner { max-width: 620px; }
|
||||
.canvas-head { flex: none; display: flex; align-items: center; gap: 10px; padding: 14px 20px; border-bottom: 1px solid var(--line-soft); }
|
||||
.canvas-head .ct { font-size: 13.5px; font-weight: 650; flex: 1; }
|
||||
.canvas-head .ctag { font-family: var(--mono); font-size: 10.5px; color: var(--healthy); background: var(--healthy-wash); padding: 4px 9px; border-radius: 7px; }
|
||||
.canvas-body { flex: 1; min-height: 0; overflow: auto; padding: 24px 26px; }
|
||||
.doc h1 { font-size: 22px; font-weight: 650; letter-spacing: -0.02em; margin: 0 0 6px; }
|
||||
.doc .docsub { font-size: 12.5px; color: var(--text-dim); font-family: var(--mono); margin-bottom: 20px; }
|
||||
.doc h2 { font-size: 13px; font-family: var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--honey); margin: 22px 0 10px; }
|
||||
.doc p { font-size: 14px; line-height: 1.62; color: var(--text-2); margin: 0 0 12px; }
|
||||
.doc table { width: 100%; border-collapse: collapse; font-size: 12.5px; margin: 6px 0 12px; }
|
||||
.doc th, .doc td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line-soft); }
|
||||
.doc th { color: var(--text-dim); font-weight: 600; font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
|
||||
.doc td { color: var(--text-2); }
|
||||
.doc td b { color: var(--text); }
|
||||
.typing-cursor::after { content:'▍'; color: var(--honey); animation: bl 1s steps(2) infinite; }
|
||||
@keyframes bl { 50% { opacity: 0; } }
|
||||
|
||||
.hidden { display: none !important; }
|
||||
@media (max-width: 820px) { body.split .canvas { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body class="split">
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Chat · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button data-v="a">A · Conversation-first</button>
|
||||
<button class="on" data-v="b">B · Split work canvas</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Split work canvas</b> — chat builds the artifact live</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="app">
|
||||
<!-- ── chat pane ── -->
|
||||
<div class="pane">
|
||||
<div class="ctx">
|
||||
<div class="wmark hex">C</div>
|
||||
<div>
|
||||
<div class="wname">Competitive Intelligence</div>
|
||||
<div class="wsub">workspace · 142 memories · 9 sources</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button class="modelpill" title="Waggle picked the model — click to override"><span class="dot dot-live"></span>Model: <b>auto</b> · Claude Sonnet</button>
|
||||
<button class="iconbtn" title="Memory & context"><svg viewBox="0 0 24 24"><path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="thread"><div class="thread-inner" id="thread"></div></div>
|
||||
|
||||
<div class="composer">
|
||||
<div class="composer-inner">
|
||||
<div class="cbox">
|
||||
<textarea rows="1" placeholder="Reply, or ask Waggle to take the next step…"></textarea>
|
||||
<button class="send">↑</button>
|
||||
</div>
|
||||
<div class="ctools">
|
||||
<button class="ctool"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg>Attach</button>
|
||||
<button class="ctool"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Persona: Analyst</button>
|
||||
<button class="ctool"><svg viewBox="0 0 24 24"><path d="M3 12h18M12 3v18"/></svg>Tools</button>
|
||||
<span class="spacer"></span>
|
||||
<span class="hint">⏎ send · ⌘K commands</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── work canvas (variation B) ── -->
|
||||
<aside class="canvas" id="canvas" style="width:42%">
|
||||
<div class="canvas-head">
|
||||
<span class="ct">teardown.md</span>
|
||||
<span class="ctag">● live draft</span>
|
||||
<button class="iconbtn" title="Open in Artifacts"><svg viewBox="0 0 24 24"><path d="M14 3h7v7M21 3l-9 9M21 14v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5"/></svg></button>
|
||||
</div>
|
||||
<div class="canvas-body">
|
||||
<div class="doc">
|
||||
<h1>Q2 Competitive Teardown</h1>
|
||||
<div class="docsub">draft · 9 competitors · updated just now by Waggle</div>
|
||||
<h2>Executive summary</h2>
|
||||
<p>The category is consolidating around persistent-memory positioning, but only two rivals ship local-first. The clearest opening is <b>regulated industries</b>, where cloud-only memory is a non-starter and no incumbent has a credible audit story.</p>
|
||||
<h2>Landscape</h2>
|
||||
<table>
|
||||
<tr><th>Player</th><th>Memory</th><th>Local-first</th></tr>
|
||||
<tr><td><b>Mem0</b></td><td>Cloud</td><td>No</td></tr>
|
||||
<tr><td><b>Letta</b></td><td>Agent-centric</td><td>Partial</td></tr>
|
||||
<tr><td><b>LangMem</b></td><td>Toy-tier</td><td>No</td></tr>
|
||||
<tr><td><b>Notion AI</b></td><td>Doc-scoped</td><td>No</td></tr>
|
||||
</table>
|
||||
<p>Pricing pulled from public pages; full table in the appendix. <span class="typing-cursor"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* theme */
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const SPARK = '<svg viewBox="0 0 24 24"><path d="M12 3v3M12 18v3M5 12H2M22 12h-3M6 6 4 4M20 20l-2-2M6 18l-2 2M20 4l-2 2"/><circle cx="12" cy="12" r="3.5"/></svg>';
|
||||
const WARN = '<svg viewBox="0 0 24 24"><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>';
|
||||
|
||||
const thread = [
|
||||
{ role:'user', who:'You', text:'Pull together a competitive teardown for Q2 — who else is selling persistent memory, and where\u2019s our opening?' },
|
||||
{ role:'bot', who:'Waggle', activity:{
|
||||
title:'Worked across <b>memory, web & files</b>', sub:'6 steps · 38s',
|
||||
steps:[
|
||||
{ c:'var(--intel)', t:'Recalled <b>6 memories</b> from your hive — last quarter\u2019s landscape, the Mem0 teardown, your pricing notes.', prov:'mem://hive · provenance kept' },
|
||||
{ c:'var(--step-web,#06b6d4)', t:'Searched <b>9 competitor sites</b> for pricing & positioning <span class="mono">(mem0, letta, langmem, notion…)</span>' },
|
||||
{ c:'var(--work)', t:'Compared against your <b>last teardown</b> — flagged 3 changes since March.' },
|
||||
{ c:'var(--healthy)', t:'Drafted <b>teardown.md</b> — exec summary, landscape table, opening.' },
|
||||
]
|
||||
},
|
||||
prose:`<p>Done. Here\u2019s the shape of it — full draft is in <b>teardown.md</b>.</p>
|
||||
<ul>
|
||||
<li><span class="b">◆</span><div>The field is consolidating on <b>persistent-memory</b> messaging, but only two rivals ship <b>local-first</b>.</div></li>
|
||||
<li><span class="b">◆</span><div>Your clearest opening is <b>regulated industries</b> — cloud-only memory is a non-starter there, and nobody has a credible audit story.</div></li>
|
||||
<li><span class="b">◆</span><div>Mem0 raised prices ~15% since March; I noted it against your pricing model.</div></li>
|
||||
</ul>
|
||||
<p>Want me to turn the opening into a one-page brief for the board, or export the table to the pricing sheet?</p>`
|
||||
},
|
||||
{ role:'user', who:'You', text:'Export the table to the Q2 pricing sheet in Salesforce.' },
|
||||
{ role:'bot', who:'Waggle', approval:{
|
||||
title:'Approve before I leave your machine',
|
||||
body:'This step writes to an external system — <span class="mono">Salesforce › Q2 Pricing</span>. Everything else stayed local. I\u2019ll export the 9-row table and nothing else.',
|
||||
} },
|
||||
];
|
||||
|
||||
function renderThread(){
|
||||
const el = document.getElementById('thread');
|
||||
el.innerHTML = thread.map((m,i) => {
|
||||
if(m.role==='user') return `<div class="msg user"><div class="av">You</div><div class="body"><div class="who"><b>You</b></div><div class="bubble">${m.text}</div></div></div>`;
|
||||
let inner = '';
|
||||
if(m.activity){
|
||||
inner += `<div class="activity ${i===1?'open':''}"><div class="ahead"><span class="spark">${SPARK}</span><span class="t">${m.activity.title} <span style="color:var(--text-dim)">· ${m.activity.sub}</span></span><span class="chev">▸</span></div><div class="steps">${
|
||||
m.activity.steps.map(s=>`<div class="astep"><span class="sd" style="background:${s.c}"></span><span class="stext">${s.t}${s.prov?`<div class="prov">⬡ ${s.prov}</div>`:''}</span></div>`).join('')
|
||||
}</div></div>`;
|
||||
}
|
||||
if(m.prose) inner += `<div class="prose">${m.prose}</div>`;
|
||||
if(m.approval) inner += `<div class="approval"><div class="ah">${WARN} ${m.approval.title}</div><p>${m.approval.body}</p><div class="actions"><button class="btn yes">Approve & export</button><button class="btn no">Not now</button></div></div>`;
|
||||
return `<div class="msg bot"><div class="av hex">W</div><div class="body"><div class="who"><b>Waggle</b> · Analyst · Claude Sonnet</div>${inner}</div></div>`;
|
||||
}).join('');
|
||||
el.querySelectorAll('.activity .ahead').forEach(h => h.onclick = () => h.parentElement.classList.toggle('open'));
|
||||
}
|
||||
renderThread();
|
||||
|
||||
/* variation switch */
|
||||
const labels = { a:'<b>Conversation-first</b> — the work reveals inline', b:'<b>Split work canvas</b> — chat builds the artifact live' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
const split = b.dataset.v==='b';
|
||||
document.body.classList.toggle('split', split);
|
||||
document.getElementById('canvas').style.width = split ? '42%' : '0px';
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,202 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Skill evolution</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
.wrap { max-width: 920px; margin: 0 auto; padding: 30px 32px 70px; }
|
||||
|
||||
.head { margin-bottom: 24px; }
|
||||
.head .eyebrow { font-family: var(--mono); font-size: 11px; letter-spacing:.14em; text-transform:uppercase; color: var(--honey); margin-bottom: 12px; display:flex; align-items:center; gap:9px; }
|
||||
.head .eyebrow::before { content:''; width:20px; height:1px; background: var(--honey-line); }
|
||||
.head h1 { font-size: 28px; font-weight: 650; letter-spacing:-0.02em; margin: 0 0 10px; }
|
||||
.head h1 em { font-style:normal; color: var(--honey); }
|
||||
.head p { font-size: 15px; color: var(--text-muted); line-height:1.55; margin:0; max-width: 64ch; } .head p b { color: var(--text-2); }
|
||||
|
||||
/* skill card + version ladder */
|
||||
.skill { border:1px solid var(--line); border-radius: var(--r-xl); background: var(--surface); overflow:hidden; }
|
||||
.skill .sh { display:flex; align-items:center; gap:13px; padding: 18px 22px; border-bottom: 1px solid var(--line-soft); }
|
||||
.skill .si { width:38px; height:42px; flex:none; display:grid; place-items:center; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.skill .si svg { width:19px; height:19px; stroke:#1a1407; fill:none; stroke-width:2; }
|
||||
.skill .sh b { font-size: 16px; font-weight: 650; } .skill .sh .sub { font-size: 12px; color: var(--text-muted); }
|
||||
.skill .sh .now { margin-left:auto; text-align:right; } .skill .sh .now .v { font-size: 24px; font-weight: 750; color: var(--honey); letter-spacing:-0.02em; } .skill .sh .now .l { font-size:10.5px; color:var(--text-dim); font-family:var(--mono); }
|
||||
|
||||
.ladder { padding: 8px 22px 18px; }
|
||||
.ver { display:grid; grid-template-columns: 64px 1fr; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--line-soft); position:relative; }
|
||||
.ver:last-child { border-bottom:0; }
|
||||
.ver .vtag { font-family: var(--mono); font-size: 12px; font-weight:600; color: var(--text-2); padding-top: 2px; }
|
||||
.ver.best .vtag { color: var(--honey); }
|
||||
.ver .vbody b { font-size: 14px; font-weight:600; }
|
||||
.ver .vbody p { margin: 4px 0 10px; font-size: 13px; color: var(--text-muted); line-height:1.5; }
|
||||
.ver .scorebar { display:flex; align-items:center; gap: 12px; }
|
||||
.ver .track { flex:1; max-width: 360px; height: 10px; border-radius: 6px; background: var(--surface-2); border:1px solid var(--line-soft); overflow:hidden; }
|
||||
.ver .fill { height:100%; border-radius:6px; background: var(--surface-3); }
|
||||
.ver.best .fill { background: linear-gradient(90deg, var(--honey-deep), var(--honey-bright)); }
|
||||
.ver .sc { font-family: var(--mono); font-size: 12.5px; font-weight:600; color: var(--text-2); } .ver.best .sc { color: var(--honey); }
|
||||
.ver .prov { margin-top: 8px; display:inline-flex; align-items:center; gap:7px; font-family:var(--mono); font-size:10.5px; color: var(--intel); }
|
||||
|
||||
.howline { margin-top: 18px; display:flex; gap:12px; align-items:flex-start; padding: 15px 17px; border-radius: var(--r-lg); background: var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.howline svg { width:18px;height:18px;stroke:var(--honey);fill:none;stroke-width:1.8;flex:none;margin-top:1px; }
|
||||
.howline p { margin:0; font-size:13px; color:var(--text-muted); line-height:1.6; } .howline b { color: var(--text); }
|
||||
|
||||
/* diffusion */
|
||||
.diffuse { display:grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
.dcard { border:1px solid var(--line-soft); border-radius: var(--r-xl); background: var(--surface); padding: 20px; }
|
||||
.dcard .dh { display:flex; align-items:center; gap:10px; margin-bottom:10px; flex-wrap:wrap; } .dcard .dh b { font-size: 15px; font-weight:650; white-space:nowrap; }
|
||||
.dcard .dh .tag { font-family:var(--mono); font-size:9.5px; letter-spacing:.1em; text-transform:uppercase; padding:3px 8px; border-radius:6px; }
|
||||
.dcard.skill-d .dh .tag { color: var(--intel); background: var(--intel-wash); }
|
||||
.dcard.tool-d .dh .tag { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.dcard .dsub { font-size: 12.5px; color: var(--text-muted); margin-bottom: 18px; }
|
||||
.map { position: relative; height: 200px; margin-bottom: 16px; }
|
||||
.map svg { position:absolute; inset:0; width:100%; height:100%; }
|
||||
.ml { stroke: var(--line-strong); stroke-width:1.3; fill:none; } .mlf { stroke-width:2.2; fill:none; stroke-linecap:round; stroke-dasharray:4 120; animation: mf 3s linear infinite; }
|
||||
.dcard.skill-d .mlf { stroke: var(--intel); } .dcard.tool-d .mlf { stroke: var(--healthy); }
|
||||
@keyframes mf { to { stroke-dashoffset:-124; } }
|
||||
.node { position:absolute; transform:translate(-50%,-50%); text-align:center; }
|
||||
.node .nb { padding: 7px 11px; border-radius: 9px; background: var(--surface-2); border:1px solid var(--line-strong); font-size:11.5px; font-weight:600; white-space:nowrap; }
|
||||
.node.origin .nb { color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); border-color:transparent; }
|
||||
.node .nt { font-family:var(--mono); font-size:8.5px; letter-spacing:.08em; text-transform:uppercase; color: var(--text-dim); margin-bottom:3px; }
|
||||
.signal { display:inline-flex; align-items:center; gap:7px; font-family:var(--mono); font-size:10.5px; padding:4px 9px; border-radius:7px; margin-bottom:12px; }
|
||||
.dcard.skill-d .signal { color:var(--intel); background:var(--intel-wash); } .dcard.tool-d .signal { color:var(--healthy); background:var(--healthy-wash); }
|
||||
.adopt { font-size: 13px; color: var(--text-2); } .adopt b { color: var(--text); font-weight:650; }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width: 800px){ .diffuse { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Moat · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Skills that improve</button>
|
||||
<button data-v="b">B · Skills & tools that spread</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Evolution</b> — skills get better on their own</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- ════ A — EVOLUTION ════ -->
|
||||
<div class="wrap view" id="view-a">
|
||||
<div class="head">
|
||||
<div class="eyebrow">The moat · self-improvement</div>
|
||||
<h1>Your skills get <em>better on their own.</em></h1>
|
||||
<p>A skill isn't static. Waggle re-optimizes it against real outcomes — and keeps every version, with the score that earned it. <b>You don't tune prompts; the hive does.</b></p>
|
||||
</div>
|
||||
|
||||
<div class="skill">
|
||||
<div class="sh">
|
||||
<div class="si hex"><svg viewBox="0 0 24 24"><path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/></svg></div>
|
||||
<div><b>Competitor teardown</b><div class="sub">skill · distilled by Research-synth · used in 4 workspaces</div></div>
|
||||
<div class="now"><div class="v">91%</div><div class="l">current quality</div></div>
|
||||
</div>
|
||||
<div class="ladder" id="ladder"></div>
|
||||
</div>
|
||||
|
||||
<div class="howline">
|
||||
<svg viewBox="0 0 24 24"><path d="M3 17l5-5 4 4 8-8M14 4h6v6"/></svg>
|
||||
<p><b>How it improves:</b> when a skill runs, Waggle's optimizer (GEPA) proposes refinements and a three-model judge scores them against held-out tasks. A new version only ships if it actually wins — and the old ones stay, so you can always roll back. Nothing about your data leaves the machine.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════ B — DIFFUSION ════ -->
|
||||
<div class="wrap view hidden" id="view-b">
|
||||
<div class="head">
|
||||
<div class="eyebrow">The moat · the waggle dance</div>
|
||||
<h1>And they <em>spread across the hive.</em></h1>
|
||||
<p>When one agent learns something good, the others don't start from zero. Skills and tool setups diffuse across your agents and workspaces — the way bees share a find. <b>The whole hive compounds.</b></p>
|
||||
</div>
|
||||
|
||||
<div class="diffuse">
|
||||
<div class="dcard skill-d">
|
||||
<div class="dh"><b>Competitor teardown</b><span class="tag">skill</span></div>
|
||||
<div class="dsub">Learned in Competitive Intelligence — now adopted elsewhere.</div>
|
||||
<div class="map">
|
||||
<svg viewBox="0 0 380 200" preserveAspectRatio="none">
|
||||
<line class="ml" x1="80" y1="100" x2="300" y2="40"></line><line class="ml" x1="80" y1="100" x2="300" y2="100"></line><line class="ml" x1="80" y1="100" x2="300" y2="160"></line>
|
||||
<line class="mlf" x1="80" y1="100" x2="300" y2="40"></line><line class="mlf" x1="80" y1="100" x2="300" y2="100" style="animation-delay:1s"></line><line class="mlf" x1="80" y1="100" x2="300" y2="160" style="animation-delay:2s"></line>
|
||||
</svg>
|
||||
<div class="node origin" style="left:21%;top:50%"><div class="nt">origin</div><div class="nb">Research-synth</div></div>
|
||||
<div class="node" style="left:79%;top:20%"><div class="nt">agent</div><div class="nb">Deck-builder</div></div>
|
||||
<div class="node" style="left:79%;top:50%"><div class="nt">workspace</div><div class="nb">Customer Research</div></div>
|
||||
<div class="node" style="left:79%;top:80%"><div class="nt">teammate</div><div class="nb">Jonas (Team)</div></div>
|
||||
</div>
|
||||
<span class="signal">⬡ waggle-dance · skill_share</span>
|
||||
<div class="adopt"><b>3 adopters</b> · 2 agents, 1 teammate — each got the v3 quality instantly.</div>
|
||||
</div>
|
||||
|
||||
<div class="dcard tool-d">
|
||||
<div class="dh"><b>Salesforce export recipe</b><span class="tag">tool setup</span></div>
|
||||
<div class="dsub">A working connector config, shared so others skip the setup.</div>
|
||||
<div class="map">
|
||||
<svg viewBox="0 0 380 200" preserveAspectRatio="none">
|
||||
<line class="ml" x1="80" y1="100" x2="300" y2="55"></line><line class="ml" x1="80" y1="100" x2="300" y2="145"></line>
|
||||
<line class="mlf" x1="80" y1="100" x2="300" y2="55"></line><line class="mlf" x1="80" y1="100" x2="300" y2="145" style="animation-delay:1.3s"></line>
|
||||
</svg>
|
||||
<div class="node origin" style="left:21%;top:50%"><div class="nt">origin</div><div class="nb">Q2 Board Deck</div></div>
|
||||
<div class="node" style="left:79%;top:28%"><div class="nt">workspace</div><div class="nb">Pricing Model</div></div>
|
||||
<div class="node" style="left:79%;top:72%"><div class="nt">workspace</div><div class="nb">Marketing Site</div></div>
|
||||
</div>
|
||||
<span class="signal">⬡ waggle-dance · model_recipe</span>
|
||||
<div class="adopt"><b>2 workspaces</b> reused the auth + field mapping — no re-setup, secrets stayed in each vault.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="howline">
|
||||
<svg viewBox="0 0 24 24"><circle cx="6" cy="7" r="2.4"/><circle cx="18" cy="7" r="2.4"/><circle cx="12" cy="17" r="2.4"/><path d="M8 8l3 7M16 8l-3 7"/></svg>
|
||||
<p><b>You stay in control:</b> diffusion is suggest-then-adopt — Waggle proposes a shared skill or recipe, you accept it per workspace. Personal stays personal; only what you share moves. On Teams, this is how a whole org levels up at once.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const vers = [
|
||||
{ v:'v1', t:'First draft', p:'Distilled from a manual teardown you did in March.', score:71 },
|
||||
{ v:'v2', t:'+ pricing-pull lane', p:'Optimizer added a step to fetch live pricing pages; judges confirmed a real lift.', score:84 },
|
||||
{ v:'v3', t:'+ source citations & recency check', p:'Every claim now carries a source and a freshness flag. Current best.', score:91, best:true, prov:'GEPA optimized · judged by 3 models' },
|
||||
];
|
||||
document.getElementById('ladder').innerHTML = vers.map(v=>`
|
||||
<div class="ver ${v.best?'best':''}">
|
||||
<div class="vtag">${v.v}</div>
|
||||
<div class="vbody">
|
||||
<b>${v.t}</b><p>${v.p}</p>
|
||||
<div class="scorebar"><div class="track"><div class="fill" style="width:${v.score}%"></div></div><span class="sc">${v.score}% quality</span></div>
|
||||
${v.prov?`<div class="prov">⬡ ${v.prov}</div>`:''}
|
||||
</div>
|
||||
</div>`).join('');
|
||||
|
||||
const labels = { a:'<b>Evolution</b> — skills get better on their own', b:'<b>Diffusion</b> — skills & tools spread across the hive' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.getElementById('view-a').classList.toggle('hidden', b.dataset.v!=='a');
|
||||
document.getElementById('view-b').classList.toggle('hidden', b.dataset.v!=='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
146
docs/design_handoff_waggle_app/design-files/screens/habit.html
Normal file
@@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Momentum</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display:flex; flex-direction:column; }
|
||||
.controls { flex:none; display:flex; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line-soft); background:color-mix(in srgb,var(--bg) 88%,transparent); backdrop-filter:blur(10px); z-index:30; }
|
||||
.controls .lab { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); }
|
||||
.controls .vlabel { font-size:12.5px; color:var(--text-muted); } .controls .vlabel b { color:var(--text); font-weight:600; }
|
||||
.controls .right { margin-left:auto; display:flex; align-items:center; gap:10px; }
|
||||
.tbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--surface); color:var(--text-2); cursor:pointer; }
|
||||
.tbtn:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.stage { flex:1; min-height:0; overflow:auto; position:relative; }
|
||||
.stage .comb { position:absolute; inset:0; opacity:.4; pointer-events:none; }
|
||||
.wrap { max-width:920px; margin:0 auto; padding:30px 32px 70px; position:relative; }
|
||||
|
||||
.head { margin-bottom:26px; }
|
||||
.head .eyebrow { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--honey); margin-bottom:12px; display:flex; align-items:center; gap:9px; }
|
||||
.head .eyebrow::before { content:''; width:20px; height:1px; background:var(--honey-line); }
|
||||
.head h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 10px; } .head h1 em { font-style:normal; color:var(--honey); }
|
||||
.head p { font-size:15px; color:var(--text-muted); line-height:1.55; margin:0; max-width:62ch; } .head p b { color:var(--text-2); }
|
||||
|
||||
/* loop diagram */
|
||||
.loop { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:14px; }
|
||||
.lstep { padding:18px; border-radius:var(--r-lg); background:var(--surface); border:1px solid var(--line-soft); position:relative; }
|
||||
.lstep .ln { font-family:var(--mono); font-size:11px; color:var(--honey); letter-spacing:.1em; margin-bottom:10px; }
|
||||
.lstep .li { width:34px; height:38px; display:grid; place-items:center; margin-bottom:11px; }
|
||||
.lstep .li svg { width:18px; height:18px; stroke:var(--honey); fill:none; stroke-width:1.7; }
|
||||
.lstep b { font-size:14.5px; font-weight:650; display:block; margin-bottom:6px; letter-spacing:-0.01em; }
|
||||
.lstep p { margin:0; font-size:12.5px; color:var(--text-muted); line-height:1.5; }
|
||||
.lstep .arr { position:absolute; right:-9px; top:50%; transform:translateY(-50%); color:var(--honey); font-size:15px; z-index:2; }
|
||||
.lstep:last-child .arr { content:'↻'; }
|
||||
|
||||
.grp { font-family:var(--mono); font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); margin:30px 0 16px; display:flex; align-items:center; gap:10px; } .grp::after { content:''; flex:1; height:1px; background:var(--line-soft); }
|
||||
|
||||
/* mechanics grid */
|
||||
.mechs { display:grid; grid-template-columns:repeat(2,1fr); gap:14px; }
|
||||
.mech { padding:22px; border-radius:var(--r-lg); background:var(--surface); border:1px solid var(--line-soft); }
|
||||
.mech.live { border-color:var(--honey-line); background:linear-gradient(155deg,var(--surface-2),var(--surface)); }
|
||||
.mech h3 { font-size:16px; font-weight:650; letter-spacing:-0.01em; margin:0 0 8px; display:flex; align-items:center; gap:10px; }
|
||||
.mech p { margin:0 0 14px; font-size:13px; color:var(--text-muted); line-height:1.55; } .mech p b { color:var(--text); }
|
||||
/* streak demo */
|
||||
.streak { display:flex; align-items:center; gap:7px; }
|
||||
.streak .d { width:30px; height:34px; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:600; color:var(--text-dim); background:var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.streak .d.on { color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); border-color:transparent; }
|
||||
.streak .d.today { box-shadow:0 0 0 2px var(--honey-line); }
|
||||
.streakcount { margin-left:6px; font-size:13px; font-weight:650; color:var(--honey); }
|
||||
/* counter demo */
|
||||
.counter { display:flex; align-items:baseline; gap:10px; }
|
||||
.counter .big { font-size:40px; font-weight:750; letter-spacing:-0.03em; color:var(--honey); }
|
||||
.counter .lab { font-size:13px; color:var(--text-muted); }
|
||||
.grow { font-size:12px; color:var(--healthy); margin-top:6px; } .grow b { color:var(--healthy); }
|
||||
/* reward demo */
|
||||
.reward { display:grid; gap:8px; }
|
||||
.rchip { display:flex; align-items:center; gap:10px; padding:9px 12px; border-radius:9px; background:var(--bg-2); border:1px solid var(--line-soft); font-size:12.5px; color:var(--text-2); }
|
||||
.rchip .dot { width:7px; height:7px; }
|
||||
.rchip b { color:var(--text); font-weight:600; }
|
||||
/* nudge demo */
|
||||
.nudge { display:flex; gap:11px; align-items:flex-start; padding:12px 14px; border-radius:10px; background:var(--honey-wash); border:1px solid var(--honey-line); }
|
||||
.nudge svg { width:16px; height:16px; stroke:var(--honey); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.nudge p { margin:0; font-size:12.5px; color:var(--text-2); line-height:1.5; } .nudge b { color:var(--text); }
|
||||
|
||||
/* ethics note */
|
||||
.ethics { margin-top:26px; display:flex; gap:13px; align-items:flex-start; padding:18px 20px; border-radius:var(--r-lg); background:var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.ethics svg { width:20px; height:20px; stroke:var(--healthy); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.ethics p { margin:0; font-size:13.5px; color:var(--text-muted); line-height:1.6; } .ethics b { color:var(--text); }
|
||||
@media (max-width:820px){ .loop { grid-template-columns:1fr 1fr; } .mechs { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Engagement · the habit loop</span>
|
||||
<span class="vlabel" id="vlabel">Momentum, not manipulation — why people come back daily</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="comb"></div>
|
||||
<div class="wrap">
|
||||
<div class="head">
|
||||
<div class="eyebrow">What makes it stick</div>
|
||||
<h1>The hive pulls you <em>back.</em></h1>
|
||||
<p>Waggle gets more valuable every day you use it — and it makes that obvious. Four honest loops turn it into a daily habit: <b>a reason to open it, a reward when you do, a visible streak, and a hive you've invested in too much to leave.</b></p>
|
||||
</div>
|
||||
|
||||
<div class="loop">
|
||||
<div class="lstep"><span class="arr">→</span><div class="li hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0"/></svg></div><div class="ln">01 · Trigger</div><b>A reason to open it</b><p>“3 things ran overnight.” A morning nudge that's always worth the tap.</p></div>
|
||||
<div class="lstep"><span class="arr">→</span><div class="li hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="ln">02 · Action</div><b>One easy move</b><p>Continue a workspace, approve a result, ask one thing. Friction near zero.</p></div>
|
||||
<div class="lstep"><span class="arr">→</span><div class="li hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/></svg></div><div class="ln">03 · Reward</div><b>Variable payoff</b><p>You never know exactly what Waggle finished — sometimes it's a small win, sometimes a big one.</p></div>
|
||||
<div class="lstep"><span class="arr" style="font-size:18px">↺</span><div class="li hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/></svg></div><div class="ln">04 · Investment</div><b>The hive grows</b><p>Every session adds memory and sharpens skills — so tomorrow is better than today.</p></div>
|
||||
</div>
|
||||
|
||||
<div class="grp">The four mechanics, made concrete</div>
|
||||
<div class="mechs">
|
||||
<div class="mech live">
|
||||
<h3>🔥 Daily streak</h3>
|
||||
<p>A gentle streak rewards showing up. Not a guilt trip — a quiet <b>“you're on a roll.”</b></p>
|
||||
<div class="streak">
|
||||
<div class="d on">M</div><div class="d on">T</div><div class="d on">W</div><div class="d on">T</div><div class="d on today">F</div><div class="d">S</div><div class="d">S</div>
|
||||
<span class="streakcount">12-day streak</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mech live">
|
||||
<h3>📈 Compounding memory</h3>
|
||||
<p>The counter that makes leaving unthinkable. The more it knows, the more <b>it's yours</b>.</p>
|
||||
<div class="counter"><span class="big">142</span><span class="lab">memories in this hive</span></div>
|
||||
<div class="grow">▲ <b>+14 this week</b> · your hive is in the top 8% by depth</div>
|
||||
</div>
|
||||
<div class="mech">
|
||||
<h3>✨ While you were away</h3>
|
||||
<p>The variable reward. Overnight work means opening Waggle is <b>always worth it</b>.</p>
|
||||
<div class="reward">
|
||||
<div class="rchip"><span class="dot" style="background:var(--healthy)"></span><b>Teardown</b> finished · 9 competitors</div>
|
||||
<div class="rchip"><span class="dot" style="background:var(--intel)"></span><b>14 memories</b> consolidated</div>
|
||||
<div class="rchip"><span class="dot" style="background:var(--work)"></span><b>2 artifacts</b> waiting for you</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mech">
|
||||
<h3>🛎️ Gentle nudges</h3>
|
||||
<p>Earned attention, never spam. A nudge only when there's <b>something real</b> to act on.</p>
|
||||
<div class="nudge"><svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 0 1-3.4 0"/></svg><p><b>Good morning, Mara.</b> Your competitor teardown is ready, and 3 memories need a quick confirm.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ethics">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/><path d="M9 12l2 2 4-4"/></svg>
|
||||
<p><b>Momentum, not manipulation.</b> Every loop here is anchored to <b>real value the user wants</b> — work that actually got done, memory that actually compounds. No dark patterns, no fake urgency, no infinite feed. The habit forms because the product genuinely gets better the more you use it; we just make that legible. Streaks and nudges can always be turned off.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
339
docs/design_handoff_waggle_app/design-files/screens/home.html
Normal file
@@ -0,0 +1,339 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Home</title>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
|
||||
/* ── Screen control bar (concept affordance, not product chrome) ── */
|
||||
.controls {
|
||||
flex: none; display: flex; align-items: center; gap: 14px;
|
||||
padding: 12px 22px; border-bottom: 1px solid var(--line-soft);
|
||||
background: color-mix(in srgb, var(--bg) 85%, transparent);
|
||||
backdrop-filter: blur(10px); z-index: 20;
|
||||
}
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); }
|
||||
.controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; position: relative; }
|
||||
.stage .comb { position: absolute; inset: 0; opacity: .5; pointer-events: none; }
|
||||
|
||||
.wrap { max-width: 920px; margin: 0 auto; padding: 46px 32px 80px; position: relative; }
|
||||
|
||||
/* ── Greeting ───────────────────────────────────────────────── */
|
||||
.greet { margin-bottom: 6px; }
|
||||
.greet .date { font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--honey); margin-bottom: 12px; display:flex; align-items:center; gap:9px; }
|
||||
.greet .date .dot { background: var(--healthy); }
|
||||
.greet .date .streakchip { margin-left: auto; padding: 4px 11px; border-radius: 999px; background: var(--honey-wash); border: 1px solid var(--honey-line); color: var(--honey); font-size: 11px; letter-spacing: .02em; text-transform: none; }
|
||||
.greet h1 { font-family: var(--sans); font-weight: 600; font-size: clamp(34px, 5vw, 52px); line-height: 1.02; letter-spacing: -0.02em; margin: 0; }
|
||||
.greet h1 em { font-style: normal; color: var(--honey); }
|
||||
|
||||
/* ── Overnight story (the hero of A) ────────────────────────── */
|
||||
.overnight {
|
||||
margin-top: 30px; padding: 28px 30px; border-radius: var(--r-xl);
|
||||
background: linear-gradient(140deg, var(--surface), var(--surface-2));
|
||||
border: 1px solid var(--line); box-shadow: var(--shadow);
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.overnight::after { content:''; position:absolute; right:-50px; top:-50px; width:200px; height:200px; background: radial-gradient(circle, var(--honey-wash), transparent 65%); pointer-events:none; }
|
||||
.overnight .tag { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--intel); display:flex; align-items:center; gap:8px; }
|
||||
.overnight .story { font-family: var(--sans); font-weight: 600; font-size: clamp(21px,2.6vw,28px); line-height: 1.32; letter-spacing: -0.01em; margin: 14px 0 0; max-width: 30ch; }
|
||||
.overnight .story b { font-style: normal; color: var(--honey); font-family: var(--sans); font-weight: 700; }
|
||||
.overnight .runs { margin-top: 22px; display: flex; flex-wrap: wrap; gap: 10px; }
|
||||
.runchip { display: inline-flex; align-items: center; gap: 8px; padding: 8px 13px; border-radius: 10px; background: var(--bg-2); border: 1px solid var(--line-soft); font-size: 13px; color: var(--text-2); }
|
||||
.runchip .dot { width: 8px; height: 8px; }
|
||||
.runchip b { color: var(--text); font-weight: 650; }
|
||||
|
||||
/* ── Section heads ──────────────────────────────────────────── */
|
||||
.sec-h { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin: 40px 0 16px; display:flex; align-items:center; gap:10px; }
|
||||
.sec-h::after { content:''; flex:1; height:1px; background: var(--line-soft); }
|
||||
|
||||
/* ── Continue cards ─────────────────────────────────────────── */
|
||||
.ws-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
|
||||
.ws-card {
|
||||
padding: 20px; border-radius: var(--r-lg); background: var(--surface);
|
||||
border: 1px solid var(--line-soft); cursor: pointer; transition: .18s; position: relative;
|
||||
}
|
||||
.ws-card:hover { border-color: var(--honey-line); transform: translateY(-3px); box-shadow: var(--shadow); }
|
||||
.ws-card .top { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; }
|
||||
.ws-card .ic { width: 34px; height: 38px; flex: none; display:grid; place-items:center; font-size: 15px; color:#1a1407; font-weight:800; }
|
||||
.ws-card h3 { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -0.01em; flex: 1; }
|
||||
.ws-card .when { font-size: 12px; color: var(--text-dim); font-family: var(--mono); }
|
||||
.ws-card p { margin: 0 0 16px; font-size: 13.5px; color: var(--text-muted); line-height: 1.5; }
|
||||
.ws-card .foot { display: flex; align-items: center; justify-content: space-between; }
|
||||
.ws-card .cont { font-size: 13px; font-weight: 650; color: var(--honey); display: inline-flex; align-items: center; gap: 5px; }
|
||||
.ws-card .badge { font-size: 11.5px; padding: 3px 9px; border-radius: 999px; display:inline-flex; align-items:center; gap:5px; }
|
||||
.ws-card .badge.pend { color: var(--attention); background: var(--honey-wash); }
|
||||
.ws-card .badge.live { color: var(--healthy); background: var(--healthy-wash); }
|
||||
|
||||
/* ── Next move / suggestions ───────────────────────────────── */
|
||||
.moves { display: grid; gap: 10px; }
|
||||
.move {
|
||||
display: flex; align-items: center; gap: 14px; padding: 15px 18px;
|
||||
border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft);
|
||||
cursor: pointer; transition: .15s;
|
||||
}
|
||||
.move:hover { border-color: var(--honey-line); background: var(--surface-2); }
|
||||
.move .mi { width: 30px; height: 30px; border-radius: 9px; flex: none; display:grid; place-items:center; }
|
||||
.move .mtext { flex: 1; }
|
||||
.move .mtext b { display:block; font-size: 14.5px; font-weight: 600; }
|
||||
.move .mtext span { font-size: 12.5px; color: var(--text-muted); }
|
||||
.move .arrow { color: var(--text-dim); font-size: 18px; transition: .15s; }
|
||||
.move:hover .arrow { color: var(--honey); transform: translateX(3px); }
|
||||
|
||||
/* ── Ask bar (B + footer of A) ─────────────────────────────── */
|
||||
.ask {
|
||||
margin-top: 28px; display: flex; align-items: center; gap: 12px;
|
||||
padding: 7px 7px 7px 20px; border-radius: 999px;
|
||||
background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
|
||||
}
|
||||
.ask:focus-within { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
|
||||
.ask input { flex: 1; background: transparent; border: 0; color: var(--text); font-family: var(--sans); font-size: 15.5px; outline: none; }
|
||||
.ask input::placeholder { color: var(--text-dim); }
|
||||
.ask .go { width: 42px; height: 42px; border-radius: 999px; border: 0; background: var(--honey); color: #1a1407; font-size: 18px; cursor: pointer; flex:none; display:grid; place-items:center; transition:.15s; }
|
||||
.ask .go:hover { background: var(--honey-bright); }
|
||||
.ask .hint { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
|
||||
/* ── Variation B — focus ───────────────────────────────────── */
|
||||
.focus-wrap { max-width: 720px; margin: 0 auto; padding: 70px 32px; text-align: center; position: relative; }
|
||||
.focus-wrap .date { justify-content: center; }
|
||||
.focus-wrap h1 { font-size: clamp(36px,5.5vw,58px); margin-bottom: 26px; }
|
||||
.focus-strip { margin-top: 30px; display: inline-flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
|
||||
.focus-resume { margin-top: 38px; display:flex; flex-direction:column; gap:10px; text-align:left; }
|
||||
|
||||
/* ── Variation C — operator dashboard ──────────────────────── */
|
||||
.dash { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; margin-top: 26px; }
|
||||
.dash .col { display: grid; gap: 16px; align-content: start; }
|
||||
.card { padding: 20px; border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); }
|
||||
.card > h4 { margin: 0 0 14px; font-size: 12px; font-family: var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); display:flex; align-items:center; gap:8px; }
|
||||
.stat-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; }
|
||||
.stat { padding: 14px; border-radius: var(--r); background: var(--bg-2); border: 1px solid var(--line-soft); }
|
||||
.stat .v { font-size: 26px; font-weight: 750; letter-spacing: -0.02em; font-family: var(--sans); line-height: 1; }
|
||||
.stat .l { font-size: 11.5px; color: var(--text-muted); margin-top: 6px; }
|
||||
.mini { display:flex; align-items:center; gap:10px; padding: 10px 0; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; }
|
||||
.mini:last-child { border-bottom: 0; }
|
||||
.mini .dot { flex: none; }
|
||||
.mini .t { flex: 1; color: var(--text-2); }
|
||||
.mini .meta { font-size: 11.5px; color: var(--text-dim); font-family: var(--mono); }
|
||||
.alert { display:flex; gap:11px; padding: 13px 15px; border-radius: var(--r); background: var(--risk-wash); border: 1px solid color-mix(in srgb, var(--risk) 30%, transparent); }
|
||||
.alert .ai { color: var(--risk); flex:none; }
|
||||
.alert b { font-size: 13.5px; }
|
||||
.alert p { margin: 3px 0 0; font-size: 12.5px; color: var(--text-muted); }
|
||||
.alert .fix { margin-left:auto; align-self:center; font-size:12px; font-weight:600; color: var(--risk); white-space:nowrap; }
|
||||
|
||||
.hidden { display: none !important; }
|
||||
svg.i { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Home · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Editorial</button>
|
||||
<button data-v="b">B · Focus</button>
|
||||
<button data-v="c">C · Operator</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Editorial briefing</b> — calm, story-led</span>
|
||||
<div class="right">
|
||||
<button class="tbtn" id="tbtn" title="Toggle theme">☾</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="comb"></div>
|
||||
|
||||
<!-- ══════════ VARIATION A — EDITORIAL ══════════ -->
|
||||
<div class="wrap view" id="view-a">
|
||||
<div class="greet">
|
||||
<div class="date"><span class="dot dot-live"></span>Friday · June 14 · 8:42<span class="streakchip" title="You've opened Waggle 12 days running">🔥 12-day streak</span></div>
|
||||
<h1>Good morning, Mara.<br>You're <em>ahead</em> of yesterday.</h1>
|
||||
</div>
|
||||
|
||||
<div class="overnight">
|
||||
<div class="tag"><span class="dot dot-live" style="background:var(--intel)"></span>While you slept</div>
|
||||
<p class="story">Waggle finished the <b>Q2 competitor teardown</b>, folded <b>14 new memories</b> into the hive, and ran into <b>one snag</b> worth a look.</p>
|
||||
<div class="runs">
|
||||
<span class="runchip"><span class="dot" style="background:var(--healthy)"></span><b>Teardown</b> drafted · 9 competitors</span>
|
||||
<span class="runchip"><span class="dot" style="background:var(--intel)"></span><b>14</b> memories consolidated</span>
|
||||
<span class="runchip"><span class="dot" style="background:var(--work)"></span><b>2</b> artifacts created</span>
|
||||
<span class="runchip"><span class="dot" style="background:var(--risk)"></span><b>1</b> export failed</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-h">Pick up where you left off</div>
|
||||
<div class="ws-grid" id="wsGridA"></div>
|
||||
|
||||
<div class="sec-h">Waggle suggests</div>
|
||||
<div class="moves" id="movesA"></div>
|
||||
|
||||
<div class="ask">
|
||||
<svg class="i" viewBox="0 0 24 24" style="color:var(--honey)"><path d="M12 3v18M3 12h18"/></svg>
|
||||
<input placeholder="Start something new — “draft the board update from this week’s work”…">
|
||||
<span class="hint">⌘K</span>
|
||||
<button class="go">→</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════════ VARIATION B — FOCUS ══════════ -->
|
||||
<div class="wrap focus-wrap view hidden" id="view-b">
|
||||
<div class="greet">
|
||||
<div class="date"><span class="dot dot-live"></span>Friday · June 14</div>
|
||||
<h1>What should we<br>work on, <em>Mara?</em></h1>
|
||||
</div>
|
||||
<div class="ask" style="max-width:620px;margin:0 auto">
|
||||
<svg class="i" viewBox="0 0 24 24" style="color:var(--honey)"><path d="M4 12h16M13 5l7 7-7 7"/></svg>
|
||||
<input placeholder="Describe a task, or pick up a thread below…" autofocus>
|
||||
<span class="hint">⌘K</span>
|
||||
<button class="go">→</button>
|
||||
</div>
|
||||
<div class="focus-strip" id="focusStrip"></div>
|
||||
|
||||
<div class="focus-resume" id="focusResume"></div>
|
||||
</div>
|
||||
|
||||
<!-- ══════════ VARIATION C — OPERATOR ══════════ -->
|
||||
<div class="wrap view hidden" id="view-c">
|
||||
<div class="greet">
|
||||
<div class="date"><span class="dot dot-live"></span>Friday · June 14 · 8:42</div>
|
||||
<h1 style="font-size:clamp(28px,3.6vw,38px)">Good morning, Mara.</h1>
|
||||
</div>
|
||||
|
||||
<div class="alert" style="margin-top:22px">
|
||||
<svg class="i ai" viewBox="0 0 24 24"><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>
|
||||
<div>
|
||||
<b>Overnight export to Salesforce failed</b>
|
||||
<p>“Q2 pipeline sync” · auth token expired at 02:14 · 1 of 4 automations</p>
|
||||
</div>
|
||||
<span class="fix">Fix & retry →</span>
|
||||
</div>
|
||||
|
||||
<div class="dash">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<h4><span class="dot dot-live" style="background:var(--intel)"></span>Overnight</h4>
|
||||
<div class="stat-row">
|
||||
<div class="stat"><div class="v" style="color:var(--intel)">14</div><div class="l">Memories consolidated</div></div>
|
||||
<div class="stat"><div class="v" style="color:var(--work)">2</div><div class="l">Artifacts created</div></div>
|
||||
<div class="stat"><div class="v" style="color:var(--healthy)">3/4</div><div class="l">Automations done</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h4>Active workspaces</h4>
|
||||
<div id="dashWs"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<h4>Up next</h4>
|
||||
<div id="dashNext"></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h4>Agents running</h4>
|
||||
<div id="dashAgents"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ── theme: sync with parent concept doc, fall back to own ──────── */
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{ localStorage.setItem('waggle-concept-theme', t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
/* ── data ───────────────────────────────────────────────────────── */
|
||||
const HONEY = 'linear-gradient(150deg,var(--honey-bright),var(--honey-deep))';
|
||||
const workspaces = [
|
||||
{ id:'ci', name:'Competitive Intelligence', glyph:'C', sum:'Q2 landscape teardown — 9 rivals mapped, pricing pulled, draft ready for your read.', when:'2h ago', badge:'pend', badgeText:'3 to review' },
|
||||
{ id:'board', name:'Q2 Board Deck', glyph:'B', sum:'18 slides drafted from the metrics pack. Narrative needs your voice on slide 6.', when:'yesterday', badge:'live', badgeText:'agent live' },
|
||||
{ id:'research', name:'Customer Research', glyph:'R', sum:'31 interviews transcribed and themed. Top friction: onboarding drop-off.', when:'2d ago', badge:null },
|
||||
{ id:'pricing', name:'Pricing Model', glyph:'P', sum:'Scenario model rebuilt. New tier lifts ARPU ~12% with low churn risk.', when:'3d ago', badge:null },
|
||||
];
|
||||
const moves = [
|
||||
{ ic:'check', col:'var(--healthy)', bg:'var(--healthy-wash)', t:'Review the competitor teardown', s:'9 competitors · ready since 02:40 · ~6 min read' },
|
||||
{ ic:'send', col:'var(--work)', bg:'var(--work-wash)', t:'Send the board update', s:'Draft built from this week’s work in Q2 Board Deck' },
|
||||
{ ic:'brain', col:'var(--intel)', bg:'var(--intel-wash)', t:'Confirm 3 imported memories', s:'From Tuesday’s pricing call — Waggle wants your sign-off' },
|
||||
];
|
||||
const next = [
|
||||
{ dot:'var(--work)', t:'Board sync', meta:'10:00' },
|
||||
{ dot:'var(--attention)', t:'Pricing review w/ Finance', meta:'13:30' },
|
||||
{ dot:'var(--healthy)', t:'“Weekly digest” automation runs', meta:'17:00' },
|
||||
];
|
||||
const agents = [
|
||||
{ dot:'var(--healthy)', t:'Research-synth', meta:'theming · 78%' },
|
||||
{ dot:'var(--work)', t:'Deck-builder', meta:'idle · waiting on you' },
|
||||
];
|
||||
const icons = {
|
||||
check:'<path d="M20 6 9 17l-5-5"/>', send:'<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',
|
||||
brain:'<path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/>'
|
||||
};
|
||||
|
||||
/* ── render A ───────────────────────────────────────────────────── */
|
||||
document.getElementById('wsGridA').innerHTML = workspaces.slice(0,4).map(w => `
|
||||
<div class="ws-card">
|
||||
<div class="top">
|
||||
<div class="ic hex" style="background:${HONEY}">${w.glyph}</div>
|
||||
<h3>${w.name}</h3>
|
||||
<span class="when">${w.when}</span>
|
||||
</div>
|
||||
<p>${w.sum}</p>
|
||||
<div class="foot">
|
||||
<span class="cont">Continue →</span>
|
||||
${w.badge ? `<span class="badge ${w.badge}">${w.badge==='live'?'<span class="dot dot-live" style="background:var(--healthy)"></span>':''}${w.badgeText}</span>` : ''}
|
||||
</div>
|
||||
</div>`).join('');
|
||||
|
||||
document.getElementById('movesA').innerHTML = moves.map(m => `
|
||||
<div class="move">
|
||||
<div class="mi" style="background:${m.bg};color:${m.col}"><svg class="i" viewBox="0 0 24 24">${icons[m.ic]}</svg></div>
|
||||
<div class="mtext"><b>${m.t}</b><span>${m.s}</span></div>
|
||||
<span class="arrow">→</span>
|
||||
</div>`).join('');
|
||||
|
||||
/* ── render B ───────────────────────────────────────────────────── */
|
||||
document.getElementById('focusStrip').innerHTML =
|
||||
`<span class="runchip"><span class="dot dot-live" style="background:var(--intel)"></span>Overnight: teardown ready · 14 memories · <b style="color:var(--risk)">1 snag</b></span>`;
|
||||
document.getElementById('focusResume').innerHTML = workspaces.slice(0,3).map(w => `
|
||||
<div class="move">
|
||||
<div class="mi hex" style="background:${HONEY};color:#1a1407;font-weight:800;border-radius:0">${w.glyph}</div>
|
||||
<div class="mtext"><b>${w.name}</b><span>${w.sum}</span></div>
|
||||
<span class="arrow">→</span>
|
||||
</div>`).join('');
|
||||
|
||||
/* ── render C ───────────────────────────────────────────────────── */
|
||||
document.getElementById('dashWs').innerHTML = workspaces.map(w => `
|
||||
<div class="mini"><span class="dot" style="background:${w.badge==='live'?'var(--healthy)':'var(--text-dim)'}"></span><span class="t">${w.name}</span><span class="meta">${w.when}</span></div>`).join('');
|
||||
document.getElementById('dashNext').innerHTML = next.map(n => `
|
||||
<div class="mini"><span class="dot" style="background:${n.dot}"></span><span class="t">${n.t}</span><span class="meta">${n.meta}</span></div>`).join('');
|
||||
document.getElementById('dashAgents').innerHTML = agents.map(a => `
|
||||
<div class="mini"><span class="dot dot-live" style="background:${a.dot}"></span><span class="t">${a.t}</span><span class="meta">${a.meta}</span></div>`).join('');
|
||||
|
||||
/* ── variation switch ───────────────────────────────────────────── */
|
||||
const labels = { a:'<b>Editorial briefing</b> — calm, story-led', b:'<b>Focus</b> — one action, minimal', c:'<b>Operator dashboard</b> — dense, for power users' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
const v = b.dataset.v;
|
||||
['a','b','c'].forEach(k => document.getElementById('view-'+k).classList.toggle('hidden', k!==v));
|
||||
document.getElementById('vlabel').innerHTML = labels[v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
287
docs/design_handoff_waggle_app/design-files/screens/ia.html
Normal file
@@ -0,0 +1,287 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Navigation</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 40; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.kbtn { display:inline-flex; align-items:center; gap:8px; font-family: var(--sans); font-size:12.5px; font-weight:600; color: var(--text-2); padding: 7px 12px; border-radius: 9px; border: 1px solid var(--line-strong); background: var(--surface); cursor: pointer; }
|
||||
.kbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.app { flex: 1; min-height: 0; display: flex; position: relative; }
|
||||
|
||||
/* ── sidebar ── */
|
||||
.side { flex: none; width: 248px; border-right: 1px solid var(--line-soft); background: var(--bg-2); display: flex; flex-direction: column; padding: 14px 12px; gap: 4px; }
|
||||
.wspill { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 11px; border: 1px solid var(--line-soft); background: var(--surface); cursor: pointer; transition:.15s; margin-bottom: 10px; }
|
||||
.wspill:hover { border-color: var(--honey-line); }
|
||||
.wspill .wm { width: 28px; height: 32px; flex:none; display:grid; place-items:center; font-weight:800; font-size:12px; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.wspill .wn { flex:1; min-width:0; } .wspill .wn b { font-size: 13px; font-weight:650; display:block; line-height:1.1; } .wspill .wn span { font-size: 11px; color: var(--text-dim); }
|
||||
.wspill .cv { color: var(--text-dim); font-size: 11px; }
|
||||
|
||||
.navitem { display: flex; align-items: center; gap: 12px; padding: 9px 11px; border-radius: 10px; cursor: pointer; color: var(--text-2); transition:.13s; position: relative; }
|
||||
.navitem:hover { background: var(--surface-2); color: var(--text); }
|
||||
.navitem.on { background: var(--honey-wash); color: var(--text); }
|
||||
.navitem.on::before { content:''; position:absolute; left:-12px; top:50%; transform:translateY(-50%); width:3px; height:18px; border-radius:3px; background: var(--honey); }
|
||||
.navitem .ni { width: 19px; height: 19px; flex:none; }
|
||||
.navitem .ni svg { width:19px; height:19px; stroke: currentColor; fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
|
||||
.navitem.on .ni svg { stroke: var(--honey); }
|
||||
.navitem .nt { flex:1; font-size: 14px; font-weight: 550; }
|
||||
.navitem .badge { font-size: 10.5px; font-family: var(--mono); color: var(--attention); background: var(--honey-wash); padding: 2px 7px; border-radius: 999px; }
|
||||
|
||||
.side .zone { font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); padding: 14px 11px 6px; display: flex; align-items: center; gap: 8px; }
|
||||
.side .pro-tier { display: none; }
|
||||
body.pro .side .pro-tier { display: block; }
|
||||
|
||||
.side .more { margin-top: 6px; }
|
||||
.cmdtile { display: flex; align-items: center; gap: 11px; padding: 10px 11px; border-radius: 10px; border: 1px dashed var(--line-strong); cursor: pointer; transition:.14s; color: var(--text-muted); }
|
||||
.cmdtile:hover { border-color: var(--honey-line); color: var(--honey); background: var(--honey-wash); }
|
||||
.cmdtile .nt { flex:1; font-size: 13px; font-weight: 600; }
|
||||
.cmdtile .kbd { font-family: var(--mono); font-size: 11px; padding: 2px 7px; border-radius: 6px; border: 1px solid var(--line-strong); background: var(--surface); color: var(--text-2); }
|
||||
|
||||
.side .spacer { flex: 1; }
|
||||
.userrow { display:flex; align-items:center; gap:10px; padding: 9px 10px; border-top: 1px solid var(--line-soft); margin-top: 6px; }
|
||||
.userrow .ua { width: 28px; height:28px; border-radius:999px; background: var(--honey); color:#1a1407; display:grid; place-items:center; font-size:11px; font-weight:700; flex:none; }
|
||||
.userrow .un { flex:1; font-size:13px; font-weight:600; }
|
||||
.userrow .ut { font-size:10.5px; color: var(--text-dim); font-family: var(--mono); }
|
||||
|
||||
/* ── main ── */
|
||||
.main { flex:1; min-width:0; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding: 40px; position: relative; }
|
||||
.main .comb { position:absolute; inset:0; opacity:.45; pointer-events:none; }
|
||||
.main .micon { width:64px; height:72px; display:grid; place-items:center; background: var(--surface); border:1px solid var(--line); margin-bottom:22px; position:relative; }
|
||||
.main .micon svg { width:30px; height:30px; stroke: var(--honey); fill:none; stroke-width:1.6; }
|
||||
.main h1 { font-size: 30px; font-weight:650; letter-spacing:-0.02em; margin:0 0 8px; position:relative; }
|
||||
.main p { font-size:15px; color: var(--text-muted); margin:0 0 24px; max-width: 42ch; position:relative; line-height:1.6; }
|
||||
.main .openk { position: relative; }
|
||||
|
||||
/* ── command palette ── */
|
||||
.palette-scrim { position: absolute; inset: 0; background: rgba(8,6,3,0.55); backdrop-filter: blur(3px); z-index: 50; display: none; align-items: flex-start; justify-content: center; padding-top: 64px; }
|
||||
body.cmd .palette-scrim { display: flex; }
|
||||
.palette { width: min(620px, 92%); background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-lg); box-shadow: var(--shadow-pop); overflow: hidden; display: flex; flex-direction: column; max-height: calc(100% - 96px); }
|
||||
.palette .pin { display: flex; align-items: center; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--line-soft); }
|
||||
.palette .pin svg { width: 18px; height: 18px; stroke: var(--text-muted); fill:none; stroke-width:1.9; flex:none; }
|
||||
.palette .pin input { flex:1; border:0; background:transparent; color: var(--text); font-family: var(--sans); font-size: 16px; outline:none; }
|
||||
.palette .pin input::placeholder { color: var(--text-dim); }
|
||||
.palette .pin .esc { font-family: var(--mono); font-size: 11px; color: var(--text-dim); border:1px solid var(--line-strong); border-radius:6px; padding:2px 7px; }
|
||||
.palette .results { overflow:auto; padding: 8px; }
|
||||
.pgroup-h { font-family: var(--mono); font-size: 10px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); padding: 12px 12px 6px; }
|
||||
.pgroup-h.pinned { color: var(--honey); }
|
||||
.presult .pinmark { color: var(--honey); }
|
||||
.presult { display:flex; align-items:center; gap:12px; padding: 9px 12px; border-radius:9px; cursor:pointer; }
|
||||
.presult:hover, .presult.sel { background: var(--honey-wash); }
|
||||
.presult .pi { width:18px; height:18px; flex:none; }
|
||||
.presult .pi svg { width:18px; height:18px; stroke: var(--text-2); fill:none; stroke-width:1.7; }
|
||||
.presult:hover .pi svg, .presult.sel .pi svg { stroke: var(--honey); }
|
||||
.presult .pt { flex:1; min-width:0; }
|
||||
.presult .pt b { font-size: 14px; font-weight: 550; }
|
||||
.presult .pt .sub { font-family: var(--mono); font-size: 11px; color: var(--text-dim); margin-left: 8px; }
|
||||
.presult .meta { font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); }
|
||||
.pempty { padding: 30px; text-align:center; color: var(--text-dim); font-size: 13px; }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width: 760px){ .side { width: 200px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body class="cmd">
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Navigation · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Calm spine</button>
|
||||
<button data-v="b">B · Pro (pinned)</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Calm spine</b> — five places, depth in ⌘K</span>
|
||||
<div class="right">
|
||||
<button class="kbtn" id="openK">⌘K · Command bar</button>
|
||||
<button class="tbtn" id="tbtn" title="Toggle theme">☾</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app">
|
||||
<!-- sidebar -->
|
||||
<nav class="side">
|
||||
<div class="wspill">
|
||||
<div class="wm hex">C</div>
|
||||
<div class="wn"><b>Competitive Intel</b><span>workspace</span></div>
|
||||
<span class="cv">⌄</span>
|
||||
</div>
|
||||
|
||||
<div class="navitem on" data-place="Home"><span class="ni"><svg viewBox="0 0 24 24"><path d="M3 11l9-8 9 8M5 10v10h14V10"/></svg></span><span class="nt">Home</span></div>
|
||||
<div class="navitem" data-place="Chat"><span class="ni"><svg viewBox="0 0 24 24"><path d="M21 12a8 8 0 0 1-11.6 7.1L3 21l1.9-6.4A8 8 0 1 1 21 12Z"/></svg></span><span class="nt">Chat</span></div>
|
||||
<div class="navitem" data-place="Memory"><span class="ni"><svg viewBox="0 0 24 24"><path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/></svg></span><span class="nt">Memory</span></div>
|
||||
<div class="navitem" data-place="Agents & tasks"><span class="ni"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9z"/></svg></span><span class="nt">Agents & tasks</span><span class="badge">2</span></div>
|
||||
<div class="navitem" data-place="Library"><span class="ni"><svg viewBox="0 0 24 24"><path d="M4 5c0-1 1-1.5 2-1.5S19 4 19 4v15s-11-.5-13 .5M4 5v15"/></svg></span><span class="nt">Library</span></div>
|
||||
|
||||
<!-- pro tier (variation B) -->
|
||||
<div class="pro-tier">
|
||||
<div class="zone">Pinned · power tools</div>
|
||||
<div class="navitem" data-place="Agent swarm"><span class="ni"><svg viewBox="0 0 24 24"><circle cx="6" cy="7" r="2.4"/><circle cx="18" cy="7" r="2.4"/><circle cx="12" cy="17" r="2.4"/><path d="M8 8l3 7M16 8l-3 7"/></svg></span><span class="nt">Agent swarm</span></div>
|
||||
<div class="navitem" data-place="Connectors"><span class="ni"><svg viewBox="0 0 24 24"><path d="M7 8a4 4 0 0 0 0 8h2M17 8a4 4 0 0 1 0 8h-2M8 12h8"/></svg></span><span class="nt">Connectors</span></div>
|
||||
<div class="navitem" data-place="Approvals"><span class="ni"><svg viewBox="0 0 24 24"><path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg></span><span class="nt">Approvals</span><span class="badge">1</span></div>
|
||||
</div>
|
||||
|
||||
<div class="more">
|
||||
<div class="zone">Everything else</div>
|
||||
<div class="cmdtile" id="openK2"><span class="nt">Search & commands</span><span class="kbd">⌘K</span></div>
|
||||
</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<div class="userrow"><div class="ua">M</div><div class="un">Mara K.<div class="ut">Pro · trial</div></div></div>
|
||||
</nav>
|
||||
|
||||
<!-- main -->
|
||||
<div class="main">
|
||||
<div class="comb"></div>
|
||||
<div class="micon hex" id="mainIcon"><svg viewBox="0 0 24 24"><path d="M3 11l9-8 9 8M5 10v10h14V10"/></svg></div>
|
||||
<h1 id="mainTitle">Home</h1>
|
||||
<p id="mainHint">Five places cover the everyday. Everything Waggle can do — the swarm, MCP servers, the optimizer, the vault — lives one keystroke away.</p>
|
||||
<button class="kbtn openk" id="openK3">Press ⌘K to find anything</button>
|
||||
</div>
|
||||
|
||||
<!-- command palette -->
|
||||
<div class="palette-scrim" id="scrim">
|
||||
<div class="palette" role="dialog" aria-label="Command bar">
|
||||
<div class="pin">
|
||||
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input id="pq" placeholder="Search places, run a command, reach any tool…" autocomplete="off">
|
||||
<span class="esc">esc</span>
|
||||
</div>
|
||||
<div class="results" id="results"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const I = {
|
||||
home:'<path d="M3 11l9-8 9 8M5 10v10h14V10"/>',
|
||||
chat:'<path d="M21 12a8 8 0 0 1-11.6 7.1L3 21l1.9-6.4A8 8 0 1 1 21 12Z"/>',
|
||||
mem:'<path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/>',
|
||||
task:'<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9z"/>',
|
||||
lib:'<path d="M4 5c0-1 1-1.5 2-1.5S19 4 19 4v15s-11-.5-13 .5M4 5v15"/>',
|
||||
plus:'<path d="M12 5v14M5 12h14"/>', import:'<path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/>',
|
||||
swarm:'<circle cx="6" cy="7" r="2.4"/><circle cx="18" cy="7" r="2.4"/><circle cx="12" cy="17" r="2.4"/><path d="M8 8l3 7M16 8l-3 7"/>',
|
||||
mcp:'<path d="M7 8a4 4 0 0 0 0 8h2M17 8a4 4 0 0 1 0 8h-2M8 12h8"/>',
|
||||
model:'<circle cx="12" cy="12" r="3.5"/><path d="M12 3v3M12 18v3M5 12H2M22 12h-3"/>',
|
||||
vault:'<rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="12" cy="12" r="3"/>',
|
||||
opt:'<path d="M3 17l5-5 4 4 8-8M14 4h6v6"/>', shield:'<path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/>',
|
||||
usage:'<path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/>', skills:'<path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/>',
|
||||
clock:'<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
|
||||
launch:'<path d="M6 4l14 8-14 8z"/>', drive:'<rect x="3" y="4" width="18" height="14" rx="2"/><path d="M3 9h18M8 21h8"/>'
|
||||
};
|
||||
const groups = [
|
||||
{ h:'Jump to', items:[
|
||||
{ ic:I.home, n:'Home', meta:'G H' }, { ic:I.chat, n:'Chat', meta:'G C' },
|
||||
{ ic:I.mem, n:'Memory', meta:'G M' }, { ic:I.task, n:'Agents & tasks', meta:'G A' },
|
||||
{ ic:I.lib, n:'Library', meta:'G L' },
|
||||
{ ic:I.opt, n:'Benchmarks', sub:'how Waggle compares · memory SOTA' },
|
||||
{ ic:I.drive, n:'All workspaces', sub:'every space you have', meta:'G W' },
|
||||
{ ic:I.home, n:'Competitive Intelligence', sub:'workspace' },
|
||||
{ ic:I.home, n:'Q2 Board Deck', sub:'workspace' },
|
||||
]},
|
||||
{ h:'Do', items:[
|
||||
{ ic:I.plus, n:'Start a task', sub:'new agent run', meta:'⌘N' },
|
||||
{ ic:I.launch, n:'Launch a coding agent', sub:'Claude Code · Cursor · Codex — shares this hive' },
|
||||
{ ic:I.import, n:'Import your history', sub:'ChatGPT · Claude · Cursor' },
|
||||
{ ic:I.usage, n:'Upgrade to Pro', sub:'plans · billing · invoices' },
|
||||
{ ic:I.shield, n:'Account & sign-in', sub:'sync, devices, SSO — optional' },
|
||||
{ ic:I.model, n:'Switch model', sub:'auto · Claude · GPT · local' },
|
||||
{ ic:I.opt, n:'Settings', sub:'models, failover, permissions, plan' },
|
||||
{ ic:I.plus, n:'Quick capture a note' },
|
||||
]},
|
||||
{ h:'Power tools — plain name, technical underneath', items:[
|
||||
{ ic:I.swarm, n:'Run a team of agents', sub:'waggle-dance · swarm' },
|
||||
{ ic:I.mcp, n:'Connect a tool', sub:'MCP servers · 21 tools' },
|
||||
{ ic:I.mcp, n:'Connectors', sub:'29 integrations' },
|
||||
{ ic:I.shield, n:'Approvals', sub:'pending agent actions' },
|
||||
{ ic:I.opt, n:'Tune the agent', sub:'GEPA optimizer' },
|
||||
{ ic:I.vault, n:'Secrets', sub:'encrypted vault' },
|
||||
{ ic:I.skills, n:'Add a capability', sub:'marketplace · skills, connectors, tools — ask the agent' },
|
||||
{ ic:I.opt, n:'Skill evolution & sharing', sub:'how skills improve & spread across the hive' },
|
||||
{ ic:I.clock, n:'Automations', sub:'scheduled jobs · 1 failing' },
|
||||
{ ic:I.drive, n:'Files & storage', sub:'where this workspace lives · local/virtual/team' },
|
||||
{ ic:I.shield, n:'Audit & compliance', sub:'EU AI Act report' },
|
||||
{ ic:I.usage, n:'Usage & cost', sub:'tokens · spend' },
|
||||
]},
|
||||
];
|
||||
|
||||
// Pinned group — only shown in Pro mode, floats the tools you live in to the top of ⌘K.
|
||||
const pinnedGroup = { h:'★ Pinned · Pro', items:[
|
||||
{ ic:I.swarm, n:'Run a team of agents', sub:'waggle-dance · swarm' },
|
||||
{ ic:I.mcp, n:'Connectors', sub:'29 integrations' },
|
||||
{ ic:I.shield, n:'Approvals', sub:'1 pending' },
|
||||
] };
|
||||
|
||||
const results = document.getElementById('results'), pq = document.getElementById('pq');
|
||||
function render(q){
|
||||
q = (q||'').toLowerCase().trim();
|
||||
let html = '', any = false;
|
||||
const active = (document.body.classList.contains('pro') ? [pinnedGroup, ...groups] : groups);
|
||||
active.forEach(g => {
|
||||
const items = g.items.filter(it => !q || (it.n+' '+(it.sub||'')).toLowerCase().includes(q));
|
||||
if(!items.length) return; any = true;
|
||||
const pin = g===pinnedGroup;
|
||||
html += `<div class="pgroup-h${pin?' pinned':''}">${g.h}</div>`;
|
||||
html += items.map(it => `<div class="presult"><span class="pi"><svg viewBox="0 0 24 24">${it.ic}</svg></span><span class="pt"><b>${it.n}</b>${it.sub?`<span class="sub">${it.sub}</span>`:''}</span>${pin?'<span class="meta pinmark">★</span>':(it.meta?`<span class="meta">${it.meta}</span>`:'')}</div>`).join('');
|
||||
});
|
||||
results.innerHTML = any ? html : '<div class="pempty">No matches — try “import”, “swarm”, “model”, “audit”…</div>';
|
||||
const first = results.querySelector('.presult'); if(first) first.classList.add('sel');
|
||||
}
|
||||
render('');
|
||||
|
||||
function openPalette(){ document.body.classList.add('cmd'); pq.value=''; render(''); setTimeout(()=>pq.focus(),30); }
|
||||
function closePalette(){ document.body.classList.remove('cmd'); }
|
||||
['openK','openK2','openK3'].forEach(id => document.getElementById(id).onclick = openPalette);
|
||||
document.getElementById('scrim').addEventListener('click', e => { if(e.target.id==='scrim') closePalette(); });
|
||||
pq.addEventListener('input', () => render(pq.value));
|
||||
addEventListener('keydown', e => {
|
||||
if((e.metaKey||e.ctrlKey) && e.key.toLowerCase()==='k'){ e.preventDefault(); document.body.classList.contains('cmd')?closePalette():openPalette(); }
|
||||
if(e.key==='Escape') closePalette();
|
||||
});
|
||||
results.addEventListener('click', e => { const r=e.target.closest('.presult'); if(r){ const n=r.querySelector('b').textContent; activate(n); closePalette(); } });
|
||||
|
||||
/* sidebar nav */
|
||||
function activate(place){
|
||||
const item = [...document.querySelectorAll('.navitem')].find(n => n.dataset.place===place);
|
||||
document.querySelectorAll('.navitem').forEach(n=>n.classList.toggle('on', n===item));
|
||||
const icMap = { 'Home':I.home, 'Chat':I.chat, 'Memory':I.mem, 'Agents & tasks':I.task, 'Library':I.lib, 'Agent swarm':I.swarm, 'Connectors':I.mcp, 'Approvals':I.shield };
|
||||
document.getElementById('mainTitle').textContent = place;
|
||||
document.getElementById('mainIcon').innerHTML = `<svg viewBox="0 0 24 24">${icMap[place]||I.home}</svg>`;
|
||||
const hints = { 'Home':'Your daily briefing — what ran overnight, what to pick back up, what\u2019s next.', 'Chat':'The work surface. Talk to your agent; the work reveals beside the thread.', 'Memory':'Everything Waggle knows about this project — with a source on every fact.', 'Agents & tasks':'What\u2019s running, what\u2019s scheduled, what finished while you were away.', 'Library':'Artifacts, files, and skills — the things you and your agents have made.' };
|
||||
document.getElementById('mainHint').textContent = hints[place] || 'A power tool, surfaced from \u2318K. In the calm spine it lives in the command bar; pin it in Pro mode.';
|
||||
}
|
||||
document.querySelectorAll('.navitem').forEach(n => n.onclick = () => activate(n.dataset.place));
|
||||
|
||||
/* variation */
|
||||
const labels = { a:'<b>Calm spine</b> — five places, depth in ⌘K', b:'<b>Pro</b> — power user pins the tools they live in' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.body.classList.toggle('pro', b.dataset.v==='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
render(pq.value);
|
||||
});
|
||||
|
||||
/* start closed */
|
||||
closePalette();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Launch agents</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
.wrap { max-width: 940px; margin: 0 auto; padding: 30px 32px 70px; }
|
||||
|
||||
.head { margin-bottom: 22px; }
|
||||
.head .crumbs { font-family: var(--mono); font-size: 11px; color: var(--text-dim); margin-bottom: 12px; }
|
||||
.head .crumbs b { color: var(--text-2); font-weight: 500; }
|
||||
.head h1 { font-size: 26px; font-weight: 650; letter-spacing: -0.02em; margin: 0 0 8px; }
|
||||
.head p { font-size: 15px; color: var(--text-muted); line-height: 1.55; margin: 0; max-width: 64ch; }
|
||||
.head p b { color: var(--text-2); font-weight: 600; }
|
||||
.platform { float: right; font-family: var(--mono); font-size: 11px; color: var(--text-2); padding: 6px 11px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); }
|
||||
|
||||
/* prompt box */
|
||||
.promptbox { margin: 20px 0; border: 1px solid var(--line); background: var(--surface); border-radius: var(--r-lg); padding: 14px 16px; }
|
||||
.promptbox .ph { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); margin-bottom: 10px; }
|
||||
.promptbox .ph svg { width: 14px; height: 14px; stroke: var(--honey); fill: none; stroke-width: 1.8; }
|
||||
.promptbox textarea { width: 100%; border: 0; background: transparent; resize: none; color: var(--text); font-family: var(--sans); font-size: 14.5px; line-height: 1.5; outline: none; min-height: 24px; }
|
||||
.promptbox textarea::placeholder { color: var(--text-dim); }
|
||||
.promptbox .pf { margin-top: 8px; font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); }
|
||||
.promptbox .pf .y { color: var(--healthy); }
|
||||
|
||||
.sec-h { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin: 26px 0 14px; display: flex; align-items: center; gap: 10px; }
|
||||
.sec-h::after { content:''; flex:1; height:1px; background: var(--line-soft); }
|
||||
.sec-h .pin { color: var(--text-2); }
|
||||
|
||||
/* tool cards */
|
||||
.tools { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
|
||||
.tool { border: 1px solid var(--line-soft); background: var(--surface); border-radius: var(--r-lg); padding: 18px; transition: .16s; }
|
||||
.tool.live { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
|
||||
.tool.off { opacity: .62; }
|
||||
.tool .top { display: flex; align-items: center; gap: 13px; }
|
||||
.tool .logo { width: 40px; height: 44px; flex: none; display: grid; place-items: center; font-family: var(--mono); font-weight: 700; font-size: 14px; color: var(--text); background: var(--surface-3); border: 1px solid var(--line); }
|
||||
.tool.live .logo { color: #1a1407; background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); border-color: transparent; }
|
||||
.tool .nm { flex: 1; min-width: 0; }
|
||||
.tool .nm b { font-size: 15.5px; font-weight: 650; letter-spacing: -0.01em; display: block; }
|
||||
.tool .nm .path { font-family: var(--mono); font-size: 11px; color: var(--text-dim); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 13px 0; }
|
||||
.bdg { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; display: inline-flex; align-items: center; gap: 5px; }
|
||||
.bdg.ok { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.bdg.hook { color: var(--attention); background: var(--honey-wash); }
|
||||
.bdg.run { color: var(--work); background: var(--work-wash); }
|
||||
.bdg.no { color: var(--text-dim); background: var(--surface-2); }
|
||||
.actions { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.abtn { font-family: var(--sans); font-size: 12.5px; font-weight: 600; padding: 8px 14px; border-radius: 9px; cursor: pointer; border: 1px solid transparent; display: inline-flex; align-items: center; gap: 6px; transition:.14s; }
|
||||
.abtn svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 2; }
|
||||
.abtn.go { background: var(--honey); color: #1a1407; }
|
||||
.abtn.go:hover { background: var(--honey-bright); }
|
||||
.abtn.ghost { background: var(--surface-2); color: var(--text-2); border-color: var(--line-strong); }
|
||||
.abtn.ghost:hover { border-color: var(--honey-line); color: var(--text); }
|
||||
.abtn.stop { background: transparent; color: var(--risk); border-color: color-mix(in srgb,var(--risk) 35%,transparent); }
|
||||
.tool .note { font-size: 12px; color: var(--text-dim); }
|
||||
|
||||
/* running panel */
|
||||
.running { margin-top: 26px; border: 1px solid var(--line-soft); border-radius: var(--r-lg); background: var(--bg-2); padding: 18px; }
|
||||
.running h3 { font-size: 13px; font-weight: 650; margin: 0 0 12px; display: flex; align-items: center; gap: 9px; }
|
||||
.running h3 .dot { background: var(--work); }
|
||||
.prow { display: grid; grid-template-columns: 1fr auto auto auto; gap: 14px; align-items: center; padding: 10px 0; border-top: 1px solid var(--line-soft); font-size: 13px; }
|
||||
.prow:first-of-type { border-top: 0; }
|
||||
.prow .pn { font-weight: 600; display:flex; align-items:center; gap:9px; }
|
||||
.prow .ws { font-size: 11.5px; color: var(--text-muted); }
|
||||
.prow .meta { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
.prow .x { color: var(--risk); cursor: pointer; font-size: 12px; font-weight: 600; }
|
||||
|
||||
/* variation B — shared memory diagram */
|
||||
.flow-wrap { border: 1px solid var(--line); border-radius: var(--r-xl); background: radial-gradient(70% 90% at 50% 0%, var(--surface), var(--bg-2)); padding: 36px; text-align: center; position: relative; overflow: hidden; }
|
||||
.flow-wrap .comb { position: absolute; inset: 0; opacity: .4; }
|
||||
.flow-row { display: flex; align-items: center; justify-content: center; gap: 0; flex-wrap: wrap; position: relative; }
|
||||
.fnode { padding: 16px 16px; border-radius: var(--r-lg); border: 1px solid var(--line-strong); background: var(--surface); min-width: 140px; max-width: 184px; }
|
||||
.fnode .ft { font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px; }
|
||||
.fnode b { font-size: 14px; font-weight: 650; }
|
||||
.fnode small { display: block; font-size: 11.5px; color: var(--text-muted); margin-top: 4px; line-height: 1.4; }
|
||||
.fnode.hive { border-color: var(--honey-line); box-shadow: var(--honey-glow); background: linear-gradient(150deg,var(--surface-2),var(--surface)); }
|
||||
.farrow { color: var(--honey); font-size: 20px; padding: 0 12px; }
|
||||
.farrow small { display:block; font-family: var(--mono); font-size: 9px; color: var(--text-dim); text-transform:uppercase; letter-spacing:.1em; }
|
||||
.flow-note { margin-top: 26px; display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
|
||||
.fc { text-align: left; padding: 16px; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft); }
|
||||
.fc .ic { width: 28px; height: 30px; display:grid; place-items:center; margin-bottom: 10px; }
|
||||
.fc .ic svg { width: 17px; height: 17px; stroke: var(--honey); fill:none; stroke-width:1.8; }
|
||||
.fc b { font-size: 13.5px; font-weight: 650; display: block; margin-bottom: 5px; }
|
||||
.fc p { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.55; }
|
||||
.prov-eg { margin-top: 18px; display:inline-flex; align-items:center; gap: 9px; font-family: var(--mono); font-size: 11.5px; color: var(--intel); background: var(--intel-wash); border: 1px solid color-mix(in srgb,var(--intel) 28%,transparent); padding: 7px 13px; border-radius: 9px; }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width: 820px){ .tools, .flow-note { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Launcher · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Launch</button>
|
||||
<button data-v="b">B · How memory is shared</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Launch</b> — detected agents, one click into this workspace</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- ════ A — LAUNCH ════ -->
|
||||
<div class="wrap view" id="view-a">
|
||||
<div class="head">
|
||||
<span class="platform">⌘ macOS · 7 tools scanned</span>
|
||||
<div class="crumbs">Competitive Intelligence <span>›</span> <b>Launch an agent</b></div>
|
||||
<h1>Bring your own agent into this workspace</h1>
|
||||
<p>Open Claude Code, Cursor, or any coding agent from here and it runs <b>wired into this workspace's memory</b> — it recalls what the hive knows, and everything it decides flows back, with provenance. Reversible hooks, nothing leaves your machine.</p>
|
||||
</div>
|
||||
|
||||
<div class="promptbox">
|
||||
<div class="ph"><svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h10"/></svg>Launch with a task <span style="color:var(--text-dim)">— optional, passed to agents that accept a prompt</span></div>
|
||||
<textarea rows="2" placeholder="e.g. “Refactor the pricing module and reconcile it against the Q2 model in memory.”"></textarea>
|
||||
<div class="pf"><span class="y">Sent to:</span> Claude Code, Cursor · <span style="color:var(--text-dim)">Ignored by:</span> Claude Desktop</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-h">Detected on this machine</div>
|
||||
<div class="tools" id="toolsLive"></div>
|
||||
|
||||
<div class="sec-h">Not installed</div>
|
||||
<div class="tools" id="toolsOff"></div>
|
||||
|
||||
<div class="running">
|
||||
<h3><span class="dot dot-live"></span>Running now · sharing this hive</h3>
|
||||
<div id="procs"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════ B — HOW MEMORY IS SHARED ════ -->
|
||||
<div class="wrap view hidden" id="view-b">
|
||||
<div class="head">
|
||||
<h1>How a launched agent shares the hive</h1>
|
||||
<p>When you launch from Waggle, the workspace's memory is wired into the external tool — no copy-paste, no re-explaining. Its work comes back attributed.</p>
|
||||
</div>
|
||||
|
||||
<div class="flow-wrap">
|
||||
<div class="comb"></div>
|
||||
<div class="flow-row">
|
||||
<div class="fnode">
|
||||
<div class="ft">You launch</div>
|
||||
<b>Claude Code</b>
|
||||
<small>opened from Waggle with<br><span class="mono" style="font-family:var(--mono);font-size:10.5px;color:var(--honey)">WAGGLE_WORKSPACE_ID</span></small>
|
||||
</div>
|
||||
<div class="farrow">⇄<small>hooks</small></div>
|
||||
<div class="fnode">
|
||||
<div class="ft">5 lifecycle hooks</div>
|
||||
<b>hive-mind</b>
|
||||
<small>session · prompt · stop · compact · tool</small>
|
||||
</div>
|
||||
<div class="farrow">⇄<small>recall + commit</small></div>
|
||||
<div class="fnode hive">
|
||||
<div class="ft">Your workspace</div>
|
||||
<b>The hive</b>
|
||||
<small>local SQLite memory<br>shared with Waggle</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-note">
|
||||
<div class="fc"><div class="ic"><svg viewBox="0 0 24 24"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/></svg></div><b>It recalls on start</b><p>The agent opens already knowing this workspace — decisions, constraints, and context, pulled from the hive.</p></div>
|
||||
<div class="fc"><div class="ic"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><b>It commits as it works</b><p>Every meaningful step is captured back into the hive, so Waggle and your next session see it too.</p></div>
|
||||
<div class="fc"><div class="ic"><svg viewBox="0 0 24 24"><path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg></div><b>Reversible & local</b><p>Hooks install and uninstall cleanly. Nothing leaves your machine; you can verify or remove them anytime.</p></div>
|
||||
</div>
|
||||
<div class="prov-eg">⬡ remembered from Claude Code · 14:22 · session a1f9</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const P = { play:'<path d="M6 4l14 8-14 8z"/>', stop:'<rect x="6" y="6" width="12" height="12" rx="1.5"/>', shield:'<path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/>', dl:'<path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/>', trash:'<path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13"/>' };
|
||||
const live = [
|
||||
{ mono:'CC', name:'Claude Code', path:'/opt/homebrew/bin/claude', installed:true, hooks:true, running:true, v:'2.4.0' },
|
||||
{ mono:'Cu', name:'Cursor', path:'/Applications/Cursor.app', installed:true, hooks:false, running:false, v:'0.51' },
|
||||
{ mono:'Cx', name:'Codex CLI', path:'/usr/local/bin/codex', installed:true, hooks:false, running:false, v:'1.2', hooksSoon:true },
|
||||
{ mono:'CD', name:'Claude Desktop', path:'/Applications/Claude.app', installed:true, hooks:false, running:false, v:'1.9', noPrompt:true },
|
||||
];
|
||||
const off = [
|
||||
{ mono:'He', name:'Hermes', note:'Not installed — install it, then re-scan.' },
|
||||
{ mono:'Oc', name:'OpenClaw', note:'Not installed — launch & hooks arrive when detected.' },
|
||||
];
|
||||
|
||||
document.getElementById('toolsLive').innerHTML = live.map(t => `
|
||||
<div class="tool ${t.running?'live':''}">
|
||||
<div class="top">
|
||||
<div class="logo">${t.mono}</div>
|
||||
<div class="nm"><b>${t.name}</b><div class="path" title="${t.path}">${t.path} · v${t.v}</div></div>
|
||||
</div>
|
||||
<div class="badges">
|
||||
<span class="bdg ok">✓ Installed</span>
|
||||
${t.hooks?'<span class="bdg hook">⬡ Hooks active</span>':(t.hooksSoon?'<span class="bdg no">hooks soon</span>':'<span class="bdg no">hooks off</span>')}
|
||||
${t.running?'<span class="bdg run"><span class="dot dot-live" style="background:var(--work)"></span>Running</span>':''}
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="abtn go"><svg viewBox="0 0 24 24">${P.play}</svg>Launch in workspace</button>
|
||||
${t.running?`<button class="abtn stop"><svg viewBox="0 0 24 24">${P.stop}</svg>Stop</button>`:''}
|
||||
${t.hooks?`<button class="abtn ghost"><svg viewBox="0 0 24 24">${P.shield}</svg>Verify</button>`:(t.hooksSoon?'':`<button class="abtn ghost"><svg viewBox="0 0 24 24">${P.dl}</svg>Install hooks</button>`)}
|
||||
</div>
|
||||
</div>`).join('');
|
||||
|
||||
document.getElementById('toolsOff').innerHTML = off.map(t => `
|
||||
<div class="tool off">
|
||||
<div class="top"><div class="logo">${t.mono}</div><div class="nm"><b>${t.name}</b><div class="path">not detected</div></div></div>
|
||||
<div class="badges"><span class="bdg no">Not installed</span></div>
|
||||
<div class="note">${t.note}</div>
|
||||
</div>`).join('');
|
||||
|
||||
document.getElementById('procs').innerHTML = `
|
||||
<div class="prow"><div class="pn"><span class="dot dot-live" style="background:var(--work)"></span>Claude Code <span class="ws">· Competitive Intelligence</span></div><span class="meta">pid 48213</span><span class="meta">12m</span><span class="x">Stop</span></div>`;
|
||||
|
||||
const labels = { a:'<b>Launch</b> — detected agents, one click into this workspace', b:'<b>How memory is shared</b> — the wiring, made legible' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.getElementById('view-a').classList.toggle('hidden', b.dataset.v!=='a');
|
||||
document.getElementById('view-b').classList.toggle('hidden', b.dataset.v!=='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Marketplace</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
|
||||
/* ════ A — MARKETPLACE ════ */
|
||||
.wrap { max-width: 960px; margin: 0 auto; padding: 28px 32px 70px; }
|
||||
.hero { text-align: center; margin-bottom: 8px; }
|
||||
.hero h1 { font-size: 28px; font-weight: 650; letter-spacing:-0.02em; margin: 0 0 8px; }
|
||||
.hero h1 em { font-style:normal; color: var(--honey); }
|
||||
.hero p { font-size: 15px; color: var(--text-muted); margin: 0 auto 22px; max-width: 50ch; line-height:1.5; }
|
||||
|
||||
/* agent-search bar */
|
||||
.ask { display:flex; align-items:center; gap:12px; max-width: 620px; margin: 0 auto 12px; padding: 10px 10px 10px 18px; border-radius: 14px; border:1px solid var(--line); background: var(--surface); box-shadow: var(--shadow); }
|
||||
.ask:focus-within { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
|
||||
.ask .sp { width:20px; height:20px; flex:none; } .ask .sp svg { width:20px; height:20px; stroke:var(--honey); fill:none; stroke-width:1.8; }
|
||||
.ask input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--sans); font-size:15.5px; outline:none; }
|
||||
.ask input::placeholder { color: var(--text-dim); }
|
||||
.ask .go { padding:10px 16px; border-radius:10px; border:0; background:var(--honey); color:#1a1407; font-size:13.5px; font-weight:650; cursor:pointer; display:inline-flex; align-items:center; gap:7px; white-space:nowrap; }
|
||||
.asexamples { display:flex; flex-wrap:wrap; gap:8px; justify-content:center; margin-bottom:8px; }
|
||||
.asx { font-size:12.5px; color:var(--text-muted); padding:6px 13px; border-radius:999px; border:1px solid var(--line-soft); background:var(--surface); cursor:pointer; transition:.14s; }
|
||||
.asx:hover { border-color:var(--honey-line); color:var(--text); }
|
||||
|
||||
/* agent result */
|
||||
.agentbox { max-width: 720px; margin: 18px auto 0; border:1px solid var(--honey-line); border-radius: var(--r-xl); background: linear-gradient(160deg,var(--surface-2),var(--surface)); overflow:hidden; box-shadow: var(--honey-glow); display:none; }
|
||||
.agentbox.show { display:block; }
|
||||
.agentbox .ah { display:flex; align-items:center; gap:11px; padding:15px 18px 11px; }
|
||||
.agentbox .ah .wm { width:28px; height:32px; flex:none; display:grid; place-items:center; font-weight:800; font-size:12px; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.agentbox .ah b { font-size:13.5px; font-weight:650; } .agentbox .ah .sub { font-family:var(--mono); font-size:11px; color:var(--text-dim); margin-left:auto; }
|
||||
.agentbox .arec { padding: 0 18px 14px; font-size:13.5px; color:var(--text-2); line-height:1.55; } .agentbox .arec b { color:var(--text); }
|
||||
.agentbox .picks { padding: 0 12px 12px; display:grid; gap:8px; }
|
||||
.pick { display:flex; align-items:center; gap:13px; padding:12px 14px; border-radius:var(--r); background:var(--surface); border:1px solid var(--line-soft); }
|
||||
.pick .pi { width:32px; height:36px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-size:10px; font-weight:700; color:var(--text-2); background:var(--surface-2); border:1px solid var(--line); }
|
||||
.pick .pt { flex:1; min-width:0; } .pick .pt b { font-size:14px; font-weight:600; } .pick .pt .ps { font-size:12px; color:var(--text-muted); }
|
||||
.pick .why { font-size:11px; color:var(--healthy); background:var(--healthy-wash); padding:3px 8px; border-radius:999px; white-space:nowrap; }
|
||||
.pick .add { font-size:12.5px; font-weight:650; padding:7px 14px; border-radius:9px; border:0; background:var(--honey); color:#1a1407; cursor:pointer; }
|
||||
.pick .add.added { background:var(--healthy-wash); color:var(--healthy); }
|
||||
|
||||
/* category filter + grid */
|
||||
.cats { display:flex; gap:7px; justify-content:center; flex-wrap:wrap; margin: 26px 0 20px; }
|
||||
.cat { font-size:12.5px; font-weight:600; color:var(--text-muted); padding:8px 14px; border-radius:999px; border:1px solid var(--line-soft); background:var(--surface); cursor:pointer; transition:.14s; }
|
||||
.cat:hover { color:var(--text); } .cat.on { color:var(--text); border-color:var(--honey-line); background:var(--honey-wash); }
|
||||
.mgrid { display:grid; grid-template-columns: repeat(3,1fr); gap:14px; }
|
||||
.mcard { padding:18px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); transition:.16s; }
|
||||
.mcard:hover { border-color:var(--honey-line); transform:translateY(-2px); box-shadow:var(--shadow); }
|
||||
.mcard .top { display:flex; align-items:center; gap:11px; margin-bottom:11px; }
|
||||
.mcard .ci { width:36px; height:40px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-size:12px; font-weight:700; color:var(--text-2); background:var(--surface-2); border:1px solid var(--line); }
|
||||
.mcard .ck { font-family:var(--mono); font-size:9.5px; letter-spacing:.08em; text-transform:uppercase; padding:3px 8px; border-radius:6px; margin-left:auto; }
|
||||
.mcard .ck.skill { color:var(--intel); background:var(--intel-wash); } .mcard .ck.conn { color:var(--healthy); background:var(--healthy-wash); } .mcard .ck.mcp { color:var(--work); background:var(--work-wash); }
|
||||
.mcard h3 { font-size:15px; font-weight:650; letter-spacing:-0.01em; margin:0 0 6px; }
|
||||
.mcard p { font-size:12.5px; color:var(--text-muted); line-height:1.5; margin:0 0 14px; min-height:36px; }
|
||||
.mcard .mf { display:flex; align-items:center; justify-content:space-between; }
|
||||
.mcard .inst { font-family:var(--mono); font-size:11px; color:var(--text-dim); }
|
||||
.mcard .add { font-size:12px; font-weight:650; padding:7px 13px; border-radius:8px; border:1px solid var(--line-strong); background:var(--surface-2); color:var(--text-2); cursor:pointer; transition:.14s; }
|
||||
.mcard .add:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.mcard .add.added { background:var(--healthy-wash); color:var(--healthy); border-color:transparent; }
|
||||
/* install states (shared by grid + picks) */
|
||||
.add.installing, .pick .add.installing { background:var(--honey-wash); color:var(--honey); border-color:var(--honey-line); cursor:default; }
|
||||
.add.done, .pick .add.done { background:var(--healthy-wash); color:var(--healthy); border-color:transparent; cursor:default; }
|
||||
.pick .add.installing { background:var(--surface-2); }
|
||||
.spin { width:11px; height:11px; border-radius:999px; border:2px solid currentColor; border-top-color:transparent; display:inline-block; margin-right:6px; vertical-align:-1px; animation:spin .7s linear infinite; }
|
||||
@keyframes spin { to { transform:rotate(360deg); } }
|
||||
/* installed-in-this-workspace bar */
|
||||
.installed-bar { display:flex; align-items:center; gap:14px; max-width:720px; margin:18px auto 0; padding:11px 16px; border-radius:var(--r-lg); background:var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.ib-count { font-family:var(--mono); font-size:12px; font-weight:600; color:var(--honey); background:var(--honey-wash); border:1px solid var(--honey-line); padding:4px 10px; border-radius:999px; white-space:nowrap; }
|
||||
.ib-chips { flex:1; display:flex; gap:6px; flex-wrap:wrap; min-width:0; }
|
||||
.ib-chip { display:inline-flex; align-items:center; gap:7px; font-size:11.5px; color:var(--text-2); padding:4px 10px; border-radius:999px; background:var(--surface); border:1px solid var(--line-soft); }
|
||||
.ib-chip .ibd { width:6px; height:6px; border-radius:999px; }
|
||||
.ib-chip .ibd.skill { background:var(--intel); } .ib-chip .ibd.conn { background:var(--healthy); } .ib-chip .ibd.mcp { background:var(--work); }
|
||||
.ib-link { font-size:12.5px; font-weight:650; color:var(--honey); text-decoration:none; white-space:nowrap; }
|
||||
.ib-link:hover { color:var(--honey-bright); }
|
||||
/* toast */
|
||||
.toast { position:fixed; bottom:22px; left:50%; transform:translateX(-50%) translateY(18px); opacity:0; pointer-events:none; display:flex; align-items:center; gap:10px; padding:12px 18px; border-radius:12px; background:var(--surface); border:1px solid var(--healthy); box-shadow:var(--shadow-lg); font-size:13.5px; color:var(--text); z-index:80; transition:.28s cubic-bezier(.16,1,.3,1); max-width:90%; }
|
||||
.toast.show { opacity:1; transform:translateX(-50%) translateY(0); }
|
||||
.toast .td { width:8px; height:8px; border-radius:999px; background:var(--healthy); flex:none; }
|
||||
.toast b { font-weight:650; }
|
||||
|
||||
/* ════ B — INLINE IN CHAT ════ */
|
||||
.chatwrap { max-width: 720px; margin: 0 auto; padding: 28px 32px 60px; }
|
||||
.chatintro { text-align:center; margin-bottom:22px; }
|
||||
.chatintro h1 { font-size:24px; font-weight:650; letter-spacing:-0.02em; margin:0 0 8px; } .chatintro h1 em { font-style:normal; color:var(--honey); }
|
||||
.chatintro p { font-size:14px; color:var(--text-muted); margin:0; }
|
||||
.msg { display:flex; gap:13px; margin-bottom:22px; }
|
||||
.msg .av { width:30px; height:34px; flex:none; display:grid; place-items:center; font-size:12px; font-weight:700; }
|
||||
.msg.user .av { background:var(--surface-3); color:var(--text-2); border-radius:9px; }
|
||||
.msg.bot .av { background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); color:#1a1407; }
|
||||
.msg .body { flex:1; min-width:0; } .msg .who { font-size:12px; color:var(--text-dim); margin-bottom:7px; }
|
||||
.msg.user .bubble { font-size:15px; line-height:1.55; color:var(--text); background:var(--surface); border:1px solid var(--line-soft); padding:12px 16px; border-radius:4px 14px 14px 14px; }
|
||||
.msg.bot .prose { font-size:15px; line-height:1.6; color:var(--text); } .msg.bot .prose p { margin:0 0 12px; }
|
||||
.inlinecard { border:1px solid var(--line); border-radius:var(--r-lg); background:var(--bg-2); padding:14px; margin-top:4px; }
|
||||
.inlinecard .ih { font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--healthy); margin-bottom:11px; display:flex; align-items:center; gap:8px; }
|
||||
.inlinecard .pick { background:var(--surface); }
|
||||
.approve-inline { display:flex; align-items:center; gap:10px; margin-top:12px; padding-top:12px; border-top:1px solid var(--line-soft); }
|
||||
.approve-inline span { font-size:12px; color:var(--text-muted); flex:1; }
|
||||
.approve-inline button { font-size:12.5px; font-weight:650; padding:8px 15px; border-radius:9px; border:0; cursor:pointer; }
|
||||
.approve-inline .yes { background:var(--honey); color:#1a1407; } .approve-inline .no { background:var(--surface-2); color:var(--text-2); border:1px solid var(--line-strong); }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width:820px){ .mgrid { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Marketplace · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Browse & ask</button>
|
||||
<button data-v="b">B · Inline in chat</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>One place</b> — skills, connectors & tools, agent-searchable</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- ════ A ════ -->
|
||||
<div class="wrap view" id="view-a">
|
||||
<div class="hero">
|
||||
<h1>Add a <em>capability.</em></h1>
|
||||
<p>Skills, connectors, and tools — one shelf. Don't know what you need? Describe the job and let the agent pick.</p>
|
||||
</div>
|
||||
|
||||
<div class="ask">
|
||||
<span class="sp"><svg viewBox="0 0 24 24"><path d="M12 3v3M12 18v3M5 12H2M22 12h-3M6 6 4 4M20 20l-2-2M6 18l-2 2M20 4l-2 2"/><circle cx="12" cy="12" r="3.5"/></svg></span>
|
||||
<input id="askInput" placeholder="Describe what you want to do…">
|
||||
<button class="go" id="askGo">Ask the agent</button>
|
||||
</div>
|
||||
<div class="asexamples" id="asex"></div>
|
||||
|
||||
<div class="agentbox" id="agentbox">
|
||||
<div class="ah"><div class="wm hex">W</div><b>Waggle suggests</b><span class="sub">3 of 412 · matched to your ask</span></div>
|
||||
<div class="arec" id="arec"></div>
|
||||
<div class="picks" id="picks"></div>
|
||||
</div>
|
||||
|
||||
<div class="installed-bar" id="instBar">
|
||||
<span class="ib-count"><span id="ibCount">0</span> in this workspace</span>
|
||||
<div class="ib-chips" id="ibChips"></div>
|
||||
<a class="ib-link" href="surfaces.html">Manage in Tools →</a>
|
||||
</div>
|
||||
|
||||
<div class="cats" id="cats"></div>
|
||||
<div class="mgrid" id="mgrid"></div>
|
||||
</div>
|
||||
|
||||
<!-- ════ B ════ -->
|
||||
<div class="chatwrap view hidden" id="view-b">
|
||||
<div class="chatintro">
|
||||
<h1>Or just <em>ask in the chat.</em></h1>
|
||||
<p>The same marketplace, surfaced inline the moment you need it — no context-switch.</p>
|
||||
</div>
|
||||
|
||||
<div class="msg user"><div class="av">You</div><div class="body"><div class="who">You</div><div class="bubble">Can you pull our open deals from Salesforce and summarize them?</div></div></div>
|
||||
|
||||
<div class="msg bot"><div class="av hex">W</div><div class="body"><div class="who">Waggle</div>
|
||||
<div class="prose"><p>I can — but I don't have a <b>Salesforce</b> connection yet. Here's the official one; it covers reading deals and contacts. Want me to add it?</p></div>
|
||||
<div class="inlinecard">
|
||||
<div class="ih">⬡ from the marketplace · 1 match</div>
|
||||
<div class="pick">
|
||||
<div class="pi">SF</div>
|
||||
<div class="pt"><b>Salesforce</b><div class="ps">CRM connector · read deals, contacts, pipeline · official</div></div>
|
||||
<span class="why">covers your ask</span>
|
||||
</div>
|
||||
<div class="approve-inline" id="inlineApprove">
|
||||
<span>Adds the connector to this workspace. You'll sign in to Salesforce; the token goes to your vault.</span>
|
||||
<button class="no">Not now</button>
|
||||
<button class="yes">Add & connect</button>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="msg bot" style="opacity:.6"><div class="av hex">W</div><div class="body"><div class="who">Waggle · after you approve</div>
|
||||
<div class="prose"><p>Connected. Pulling your open deals now — 23 found, summarizing by stage…</p></div>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const items = [
|
||||
{ id:'sf', mono:'SF', k:'conn', cat:'Connectors', n:'Salesforce', d:'Read deals, contacts, and pipeline from your CRM.', inst:'12k installs' },
|
||||
{ id:'notion', mono:'No', k:'conn', cat:'Connectors', n:'Notion', d:'Search and write docs, wikis, and databases.', inst:'31k installs' },
|
||||
{ id:'slack', mono:'Sl', k:'conn', cat:'Connectors', n:'Slack', d:'Post updates and read channels your agent watches.', inst:'44k installs' },
|
||||
{ id:'teardown', mono:'★', k:'skill', cat:'Skills', n:'Competitor teardown', d:'Structured rival analysis with pricing pull and citations.', inst:'self-evolving' },
|
||||
{ id:'brief', mono:'★', k:'skill', cat:'Skills', n:'Board brief writer', d:'Turn a workspace into a tight one-page board narrative.', inst:'8k installs' },
|
||||
{ id:'interview', mono:'★', k:'skill', cat:'Skills', n:'Interview synthesizer', d:'Theme and quote-mine user interviews at scale.', inst:'6k installs' },
|
||||
{ id:'fs', mono:'fs', k:'mcp', cat:'MCP servers', n:'Filesystem', d:'Let agents read and write workspace files safely.', inst:'official' },
|
||||
{ id:'web', mono:'web', k:'mcp', cat:'MCP servers', n:'Web search', d:'Live retrieval from the open web during a task.', inst:'official' },
|
||||
{ id:'gh', mono:'Gh', k:'conn', cat:'Connectors', n:'GitHub', d:'Issues, PRs, and repo context for engineering work.', inst:'28k installs' },
|
||||
];
|
||||
const KLABEL = { skill:'skill', conn:'connector', mcp:'MCP' };
|
||||
// Per-type one-click verbs: [idle, in-progress, done] — each install does the right thing.
|
||||
const VERB = { skill:['Add','Adding…','Added'], conn:['Connect','Signing in…','Connected'], mcp:['Enable','Enabling…','Enabled'] };
|
||||
|
||||
/* ── Single source of truth: install state shared by grid, picks & chat ── */
|
||||
const installed = new Set(['fs','web','gh']); // already in this workspace (matches the Tools surface)
|
||||
const installing = new Set();
|
||||
|
||||
function btnHTML(it, cls){
|
||||
const v = VERB[it.k];
|
||||
if(installed.has(it.id)) return `<button class="${cls} done" data-id="${it.id}" disabled>✓ ${v[2]}</button>`;
|
||||
if(installing.has(it.id)) return `<button class="${cls} installing" data-id="${it.id}" disabled><span class="spin"></span>${v[1]}</button>`;
|
||||
return `<button class="${cls}" data-id="${it.id}">+ ${v[0]}</button>`;
|
||||
}
|
||||
|
||||
function toast(it){
|
||||
const t = document.getElementById('toast');
|
||||
const verb = it.k==='conn'?'connected':it.k==='mcp'?'enabled':'added';
|
||||
t.innerHTML = `<span class="td"></span><span><b>${it.n}</b> ${verb} · now available to your agents here</span>`;
|
||||
t.classList.add('show'); clearTimeout(t._t); t._t = setTimeout(()=>t.classList.remove('show'), 2700);
|
||||
}
|
||||
|
||||
/* One-click install — connector signs in (longer), MCP enables tools, skill is instant. Then SYNC everywhere. */
|
||||
function install(id){
|
||||
const it = items.find(x=>x.id===id);
|
||||
if(!it || installed.has(id) || installing.has(id)) return;
|
||||
installing.add(id); renderAll();
|
||||
const ms = it.k==='skill' ? 480 : it.k==='mcp' ? 720 : 1100;
|
||||
setTimeout(()=>{ installing.delete(id); installed.add(id); renderAll(); toast(it); }, ms);
|
||||
}
|
||||
|
||||
let cat = 'All';
|
||||
const cats = ['All','Skills','Connectors','MCP servers'];
|
||||
document.getElementById('cats').innerHTML = cats.map(c=>`<span class="cat ${c==='All'?'on':''}" data-c="${c}">${c}</span>`).join('');
|
||||
|
||||
function renderGrid(){
|
||||
const list = items.filter(it => cat==='All' || it.cat===cat);
|
||||
document.getElementById('mgrid').innerHTML = list.map(it=>`
|
||||
<div class="mcard">
|
||||
<div class="top"><div class="ci">${it.mono}</div><span class="ck ${it.k}">${KLABEL[it.k]}</span></div>
|
||||
<h3>${it.n}</h3><p>${it.d}</p>
|
||||
<div class="mf"><span class="inst">${it.inst}</span>${btnHTML(it,'add')}</div>
|
||||
</div>`).join('');
|
||||
}
|
||||
function renderPicks(){
|
||||
if(!currentPicks) return;
|
||||
document.getElementById('picks').innerHTML = currentPicks.map(id=>{ const it=items.find(x=>x.id===id); return `
|
||||
<div class="pick"><div class="pi">${it.mono}</div><div class="pt"><b>${it.n}</b><div class="ps">${KLABEL[it.k]} · ${it.d}</div></div><span class="why">why: ${it.k==='conn'?'reaches your data':it.k==='skill'?'does the work':'needed tool'}</span>${btnHTML(it,'add')}</div>`; }).join('');
|
||||
}
|
||||
function renderBar(){
|
||||
document.getElementById('ibCount').textContent = installed.size;
|
||||
document.getElementById('ibChips').innerHTML = [...installed].map(id=>{ const it=items.find(x=>x.id===id); return `<span class="ib-chip"><span class="ibd ${it.k}"></span>${it.n}</span>`; }).join('');
|
||||
}
|
||||
function renderAll(){ renderGrid(); renderPicks(); renderBar(); renderInline(); }
|
||||
|
||||
renderGrid(); renderBar();
|
||||
document.getElementById('cats').addEventListener('click', e=>{ const c=e.target.closest('.cat'); if(!c)return; cat=c.dataset.c; document.querySelectorAll('.cat').forEach(x=>x.classList.toggle('on',x===c)); renderGrid(); });
|
||||
|
||||
// one delegated handler powers every install button on the page → guaranteed in sync
|
||||
document.addEventListener('click', e=>{ const b=e.target.closest('button.add[data-id]'); if(b && !b.disabled) install(b.dataset.id); });
|
||||
|
||||
// agent search
|
||||
let currentPicks = null;
|
||||
const examples = ['Summarize our Salesforce pipeline','Analyze 3 competitors','Theme our user interviews','Post a daily digest to Slack'];
|
||||
document.getElementById('asex').innerHTML = examples.map(x=>`<span class="asx">${x}</span>`).join('');
|
||||
const recs = {
|
||||
default: { rec:'Based on “<b>__Q__</b>”, these three cover it — a connector to reach your data, a skill to do the analysis, and the tool they need.', picks:['sf','teardown','web'] },
|
||||
interview: { rec:'For interview work, you mainly need the <b>synthesizer skill</b>; it works on files already in your workspace.', picks:['interview','fs'] },
|
||||
slack: { rec:'To post to Slack you need the <b>Slack connector</b>; pair it with an automation to send on a schedule.', picks:['slack'] },
|
||||
};
|
||||
function runAsk(q){
|
||||
const ql = q.toLowerCase();
|
||||
let r = recs.default;
|
||||
if(ql.includes('interview')) r = recs.interview;
|
||||
else if(ql.includes('slack') || ql.includes('digest')) r = recs.slack;
|
||||
document.getElementById('arec').innerHTML = r.rec.replace('__Q__', q || 'your task');
|
||||
currentPicks = r.picks;
|
||||
renderPicks();
|
||||
document.getElementById('agentbox').classList.add('show');
|
||||
}
|
||||
document.getElementById('askGo').onclick = () => runAsk(document.getElementById('askInput').value);
|
||||
document.getElementById('askInput').addEventListener('keydown', e=>{ if(e.key==='Enter') runAsk(e.target.value); });
|
||||
document.getElementById('asex').addEventListener('click', e=>{ const x=e.target.closest('.asx'); if(x){ document.getElementById('askInput').value=x.textContent; runAsk(x.textContent); } });
|
||||
|
||||
// inline-in-chat install — shares the SAME state, so adding here updates the browse view too
|
||||
function renderInline(){
|
||||
const wrap = document.getElementById('inlineApprove'); if(!wrap) return;
|
||||
if(installed.has('sf')) wrap.innerHTML = '<span style="color:var(--healthy)">✓ Salesforce connected — token saved to your vault. Pulling your open deals…</span>';
|
||||
else if(installing.has('sf')) wrap.innerHTML = '<span style="color:var(--honey)"><span class="spin"></span>Signing in to Salesforce…</span>';
|
||||
}
|
||||
document.querySelector('#view-b .approve-inline .yes')?.addEventListener('click', ()=> install('sf'));
|
||||
|
||||
// variation switch
|
||||
const labels = { a:'<b>Browse & ask</b> — one shelf, the agent picks for you', b:'<b>Inline in chat</b> — surfaced the moment you need it' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.getElementById('view-a').classList.toggle('hidden', b.dataset.v!=='a');
|
||||
document.getElementById('view-b').classList.toggle('hidden', b.dataset.v!=='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,227 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Memory Trust</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
|
||||
.controls { flex:none; display:flex; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line-soft); background:color-mix(in srgb,var(--bg) 88%,transparent); backdrop-filter:blur(10px); z-index:30; }
|
||||
.controls .lab { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); }
|
||||
.seg { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.seg button { font-family:var(--sans); font-size:12.5px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:6px 13px; border-radius:7px; transition:.14s; white-space:nowrap; }
|
||||
.seg button.on { background:var(--honey); color:#1a1407; }
|
||||
.controls .vlabel { font-size:12.5px; color:var(--text-muted); } .controls .vlabel b { color:var(--text); font-weight:600; }
|
||||
.controls .right { margin-left:auto; display:flex; align-items:center; gap:10px; }
|
||||
.tbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--surface); color:var(--text-2); cursor:pointer; }
|
||||
.tbtn:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.stage { flex:1; min-height:0; overflow:auto; }
|
||||
.wrap { max-width:920px; margin:0 auto; padding:30px 32px 70px; }
|
||||
.view { display:none; } .view.on { display:block; }
|
||||
|
||||
.head { margin-bottom:22px; }
|
||||
.head .eyebrow { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--honey); margin-bottom:12px; display:flex; align-items:center; gap:9px; } .head .eyebrow::before { content:''; width:20px; height:1px; background:var(--honey-line); }
|
||||
.head h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 10px; } .head h1 em { font-style:normal; color:var(--honey); }
|
||||
.head p { font-size:15px; color:var(--text-muted); line-height:1.55; margin:0; max-width:64ch; } .head p b { color:var(--text-2); }
|
||||
|
||||
/* trust summary bar */
|
||||
.tsum { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:24px; }
|
||||
.ts { padding:16px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); }
|
||||
.ts .v { font-size:24px; font-weight:750; letter-spacing:-0.02em; } .ts .l { font-size:11.5px; color:var(--text-muted); margin-top:5px; }
|
||||
.ts.warn { border-color:color-mix(in srgb,var(--attention) 35%,transparent); } .ts.warn .v { color:var(--attention); }
|
||||
|
||||
.toolbar { display:flex; align-items:center; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
|
||||
.search { flex:1; min-width:200px; display:flex; align-items:center; gap:10px; padding:9px 14px; border-radius:11px; border:1px solid var(--line); background:var(--surface); }
|
||||
.search svg { width:16px; height:16px; stroke:var(--text-dim); fill:none; stroke-width:1.9; }
|
||||
.search input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--sans); font-size:14px; outline:none; }
|
||||
.filt { font-size:12.5px; font-weight:600; color:var(--text-muted); padding:8px 13px; border-radius:9px; border:1px solid var(--line-soft); background:var(--surface); cursor:pointer; transition:.14s; }
|
||||
.filt:hover { color:var(--text); } .filt.on { color:var(--text); border-color:var(--honey-line); background:var(--honey-wash); }
|
||||
|
||||
/* memory rows */
|
||||
.mems { display:grid; gap:10px; }
|
||||
.mem { border:1px solid var(--line-soft); background:var(--surface); border-radius:var(--r-lg); padding:16px 18px; transition:.15s; }
|
||||
.mem.stale { border-color:color-mix(in srgb,var(--attention) 30%,var(--line-soft)); }
|
||||
.mem.disputed { border-color:color-mix(in srgb,var(--risk) 30%,var(--line-soft)); opacity:.92; }
|
||||
.mem .top { display:flex; align-items:flex-start; gap:13px; }
|
||||
.mem .conf { width:42px; flex:none; text-align:center; }
|
||||
.mem .conf .ring { width:38px; height:38px; border-radius:999px; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:600; }
|
||||
.mem .conf .cl { font-size:9px; color:var(--text-dim); font-family:var(--mono); margin-top:4px; text-transform:uppercase; letter-spacing:.06em; }
|
||||
.mem .mbody { flex:1; min-width:0; }
|
||||
.mem .mtext { font-size:14.5px; line-height:1.5; color:var(--text); } .mem .mtext b { font-weight:650; }
|
||||
.mem.disputed .mtext { text-decoration:line-through; text-decoration-color:color-mix(in srgb,var(--risk) 60%,transparent); color:var(--text-muted); }
|
||||
.mem .prov { margin-top:8px; display:flex; flex-wrap:wrap; gap:7px 14px; align-items:center; font-family:var(--mono); font-size:10.5px; color:var(--text-dim); }
|
||||
.mem .prov .src { color:var(--intel); } .mem .prov .fresh.ok { color:var(--healthy); } .mem .prov .fresh.old { color:var(--attention); }
|
||||
.mem .acts { display:flex; gap:6px; align-items:center; flex:none; }
|
||||
.mact { width:30px; height:30px; border-radius:8px; border:1px solid var(--line-soft); background:var(--surface-2); color:var(--text-muted); cursor:pointer; display:grid; place-items:center; transition:.14s; }
|
||||
.mact:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.mact.danger:hover { border-color:color-mix(in srgb,var(--risk) 45%,transparent); color:var(--risk); }
|
||||
.mact svg { width:15px; height:15px; stroke:currentColor; fill:none; stroke-width:1.8; }
|
||||
.corrected { margin-top:10px; padding:9px 13px; border-radius:9px; background:var(--healthy-wash); border:1px solid color-mix(in srgb,var(--healthy) 30%,transparent); font-size:12.5px; color:var(--text-2); display:flex; gap:9px; align-items:center; }
|
||||
.corrected svg { width:14px; height:14px; stroke:var(--healthy); fill:none; stroke-width:2; flex:none; }
|
||||
.corrected b { color:var(--text); }
|
||||
.stalebanner { margin-top:10px; padding:9px 13px; border-radius:9px; background:var(--honey-wash); border:1px solid var(--honey-line); font-size:12.5px; color:var(--text-2); display:flex; gap:9px; align-items:center; }
|
||||
.stalebanner svg { width:14px; height:14px; stroke:var(--honey); fill:none; stroke-width:2; flex:none; }
|
||||
.stalebanner .sp { margin-left:auto; display:flex; gap:6px; }
|
||||
.sbtn { font-size:11.5px; font-weight:650; padding:5px 11px; border-radius:7px; cursor:pointer; border:1px solid transparent; }
|
||||
.sbtn.go { background:var(--honey); color:#1a1407; } .sbtn.ghost { background:var(--surface); color:var(--text-2); border-color:var(--line-strong); }
|
||||
|
||||
/* why-trace (variation B) */
|
||||
.trace { border:1px solid var(--line); border-radius:var(--r-xl); background:var(--bg-2); overflow:hidden; }
|
||||
.trace .th { display:flex; align-items:center; gap:12px; padding:18px 22px; border-bottom:1px solid var(--line-soft); }
|
||||
.trace .th .ti { width:34px; height:38px; flex:none; display:grid; place-items:center; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.trace .th .ti svg { width:18px; height:18px; stroke:#1a1407; fill:none; stroke-width:2; }
|
||||
.trace .th b { font-size:15.5px; font-weight:650; } .trace .th .sub { font-size:12px; color:var(--text-muted); }
|
||||
.trace .th .when { margin-left:auto; font-family:var(--mono); font-size:11px; color:var(--text-dim); }
|
||||
.tchain { padding:8px 22px 18px; }
|
||||
.tnode { display:grid; grid-template-columns:24px 1fr; gap:14px; padding:14px 0; position:relative; }
|
||||
.tnode::before { content:''; position:absolute; left:11px; top:34px; bottom:-14px; width:1.5px; background:var(--line); }
|
||||
.tnode:last-child::before { display:none; }
|
||||
.tnode .tdot { width:24px; height:24px; border-radius:999px; display:grid; place-items:center; flex:none; z-index:1; }
|
||||
.tnode .tdot svg { width:13px; height:13px; stroke:#1a1407; fill:none; stroke-width:2.4; }
|
||||
.tnode .tc b { font-size:13.5px; font-weight:600; } .tnode .tc p { margin:4px 0 0; font-size:13px; color:var(--text-muted); line-height:1.5; } .tnode .tc p .mono { font-family:var(--mono); font-size:11.5px; color:var(--text-dim); } .tnode .tc p .src { color:var(--intel); font-family:var(--mono); font-size:11px; }
|
||||
.tnode .tc .ev { margin-top:7px; font-size:12px; color:var(--text-2); padding:8px 12px; border-radius:8px; background:var(--surface); border:1px solid var(--line-soft); }
|
||||
.traceact { display:flex; gap:9px; padding:16px 22px; border-top:1px solid var(--line-soft); background:var(--surface); }
|
||||
.tbtn2 { font-size:12.5px; font-weight:650; padding:9px 15px; border-radius:9px; cursor:pointer; border:1px solid transparent; }
|
||||
.tbtn2.go { background:var(--honey); color:#1a1407; } .tbtn2.ghost { background:var(--surface-2); color:var(--text-2); border-color:var(--line-strong); } .tbtn2.danger { background:transparent; color:var(--risk); border-color:color-mix(in srgb,var(--risk) 35%,transparent); }
|
||||
|
||||
.principle { margin-top:24px; display:flex; gap:13px; align-items:flex-start; padding:18px 20px; border-radius:var(--r-lg); background:var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.principle svg { width:20px; height:20px; stroke:var(--healthy); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.principle p { margin:0; font-size:13.5px; color:var(--text-muted); line-height:1.6; } .principle b { color:var(--text); }
|
||||
|
||||
.toast { position:fixed; bottom:22px; left:50%; transform:translateX(-50%) translateY(18px); opacity:0; pointer-events:none; display:flex; align-items:center; gap:10px; padding:12px 18px; border-radius:12px; background:var(--surface); border:1px solid var(--healthy); box-shadow:var(--shadow-lg); font-size:13.5px; color:var(--text); z-index:80; transition:.28s cubic-bezier(.16,1,.3,1); }
|
||||
.toast.show { opacity:1; transform:translateX(-50%) translateY(0); }
|
||||
.toast .td2 { width:8px; height:8px; border-radius:999px; background:var(--healthy); flex:none; }
|
||||
@media (max-width:820px){ .tsum { grid-template-columns:1fr 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Memory Trust · view</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="manage">Manage memory</button>
|
||||
<button data-v="why">Why did you do that?</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Manage</b> — forget, correct, confirm; see confidence & freshness</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- ════ A — MANAGE ════ -->
|
||||
<div class="view on wrap" data-view="manage">
|
||||
<div class="head">
|
||||
<div class="eyebrow">Trust · the thing that makes you stay</div>
|
||||
<h1>Memory you can <em>correct, age, and forget.</em></h1>
|
||||
<p>A memory that only grows is a liability. Waggle shows you <b>how sure it is</b>, <b>how fresh it is</b>, and <b>where it came from</b> — and lets you fix or forget anything. You're always in control of what the hive believes.</p>
|
||||
</div>
|
||||
|
||||
<div class="tsum">
|
||||
<div class="ts"><div class="v">142</div><div class="l">Memories in this hive</div></div>
|
||||
<div class="ts"><div class="v" style="color:var(--healthy)">128</div><div class="l">High confidence & fresh</div></div>
|
||||
<div class="ts warn"><div class="v">9</div><div class="l">Stale · worth a review</div></div>
|
||||
<div class="ts warn"><div class="v">3</div><div class="l">Awaiting your confirm</div></div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg><input placeholder="Search what Waggle knows… or ask it to forget something"></div>
|
||||
<span class="filt on">All</span><span class="filt">Stale</span><span class="filt">Needs confirm</span><span class="filt">Forgotten</span>
|
||||
</div>
|
||||
|
||||
<div class="mems" id="mems"></div>
|
||||
|
||||
<div class="principle">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/><path d="M9 12l2 2 4-4"/></svg>
|
||||
<p><b>Nothing is remembered behind your back.</b> Every memory is inspectable, editable, and forgettable — and forgetting is real: it's removed from recall and from anything Waggle says next. Confidence and freshness are shown so the agent (and you) can discount what's old or shaky instead of acting on it blindly.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════ B — WHY TRACE ════ -->
|
||||
<div class="view wrap" data-view="why">
|
||||
<div class="head">
|
||||
<div class="eyebrow">Provenance · accountability</div>
|
||||
<h1>Ask the agent <em>“why did you do that?”</em></h1>
|
||||
<p>Any action an agent takes can be traced back to the exact memories and sources behind it — so a wrong move is <b>diagnosable, not mysterious</b>. If a bad memory caused it, fix the memory right from the trace.</p>
|
||||
</div>
|
||||
|
||||
<div class="trace">
|
||||
<div class="th">
|
||||
<div class="ti hex"><svg viewBox="0 0 24 24"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg></div>
|
||||
<div><b>Drafted the board brief around “regulated industries”</b><div class="sub">Deck-builder · 18m ago · Q2 Board Deck</div></div>
|
||||
<span class="when">trace #a1f9</span>
|
||||
</div>
|
||||
<div class="tchain">
|
||||
<div class="tnode"><div class="tdot" style="background:var(--intel)"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="tc"><b>Goal received</b><p>You asked: <span class="mono">“tighten the board narrative.”</span></p></div></div>
|
||||
<div class="tnode"><div class="tdot" style="background:var(--honey)"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></div><div class="tc"><b>Recalled 3 memories</b><p>Strongest was: <span class="src">⬡ mem #M-204</span> — “Mara wants market work to lead with the regulated-industries angle.”</p><div class="ev">confidence 94% · source: chat · Tue · still fresh</div></div></div>
|
||||
<div class="tnode"><div class="tdot" style="background:var(--honey)"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></div><div class="tc"><b>Cross-checked the teardown</b><p>Confirmed 2 of 3 proof points cite customer quotes <span class="src">⬡ teardown.md</span></p></div></div>
|
||||
<div class="tnode"><div class="tdot" style="background:var(--healthy)"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div><div class="tc"><b>Acted</b><p>Wrote slide 6 around the regulated angle and flagged it for your review.</p></div></div>
|
||||
</div>
|
||||
<div class="traceact">
|
||||
<button class="tbtn2 go">Looks right</button>
|
||||
<button class="tbtn2 ghost">That memory is wrong → correct it</button>
|
||||
<button class="tbtn2 danger">Forget #M-204 & redo</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="principle">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 8h.01M11 12h1v4h1"/></svg>
|
||||
<p><b>Every agent action keeps its trace.</b> The chain from goal → recalled memories → checks → action is stored with the result, so "why did you do that?" always has an answer — and the fix (correct or forget the offending memory) is one click from the explanation.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"><span class="td2"></span><span id="toastText"></span></div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
function confColor(c){ return c>=85?'var(--healthy)':c>=60?'var(--attention)':'var(--risk)'; }
|
||||
const mems = [
|
||||
{ id:'M-204', text:'Mara wants market work to <b>lead with the regulated-industries angle</b>.', conf:94, src:'chat · Tue', fresh:'fresh', state:'ok' },
|
||||
{ id:'M-198', text:'<b>Mem0</b> is cloud-only and raised prices ~15% in March.', conf:88, src:'web · mem0.ai', fresh:'fresh', state:'ok' },
|
||||
{ id:'M-141', text:'The Q3 launch date is <b>September 12</b>.', conf:61, src:'chat · 6 weeks ago', fresh:'old', state:'stale' },
|
||||
{ id:'M-088', text:'Mara prefers <b>Slack over email</b> for updates.', conf:47, src:'inferred · once', fresh:'old', state:'disputed', corrected:'Corrected by you → prefers a daily digest, not Slack pings.' },
|
||||
{ id:'M-052', text:'Primary competitor is <b>Letta</b>.', conf:90, src:'teardown.md', fresh:'fresh', state:'ok' },
|
||||
];
|
||||
const FRESH = { fresh:['ok','fresh'], old:['old','aging'] };
|
||||
function row(m){
|
||||
const stale = m.state==='stale', disp = m.state==='disputed';
|
||||
return `<div class="mem ${m.state}">
|
||||
<div class="top">
|
||||
<div class="conf"><div class="ring" style="color:${confColor(m.conf)};border:2px solid ${confColor(m.conf)}">${m.conf}</div><div class="cl">conf</div></div>
|
||||
<div class="mbody">
|
||||
<div class="mtext">${m.text}</div>
|
||||
<div class="prov"><span><span class="src">⬡ ${m.id}</span></span><span>source: ${m.src}</span><span class="fresh ${m.fresh==='fresh'?'ok':'old'}">● ${m.fresh==='fresh'?'fresh':'aging — last seen 6w ago'}</span></div>
|
||||
${disp&&m.corrected?`<div class="corrected"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg><span><b>${m.corrected.split('→')[0].trim()}</b> → ${m.corrected.split('→')[1].trim()}</span></div>`:''}
|
||||
${stale?`<div class="stalebanner"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg><span>This is 6 weeks old — still true?</span><span class="sp"><button class="sbtn go" data-act="confirm" data-id="${m.id}">Still true</button><button class="sbtn ghost" data-act="forget" data-id="${m.id}">Forget</button></span></div>`:''}
|
||||
</div>
|
||||
<div class="acts">
|
||||
<button class="mact" title="Edit / correct" data-act="edit" data-id="${m.id}"><svg viewBox="0 0 24 24"><path d="M14 7l-1.5-1.5a2 2 0 0 0-3 0l-5 5L4 14l3.5-.5 5-5a2 2 0 0 0 0-3z"/></svg></button>
|
||||
<button class="mact danger" title="Forget this" data-act="forget" data-id="${m.id}"><svg viewBox="0 0 24 24"><path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
document.getElementById('mems').innerHTML = mems.map(row).join('');
|
||||
|
||||
function toast(msg){ const t=document.getElementById('toast'); document.getElementById('toastText').textContent=msg; t.classList.add('show'); clearTimeout(t._t); t._t=setTimeout(()=>t.classList.remove('show'),2400); }
|
||||
document.getElementById('mems').addEventListener('click', e=>{
|
||||
const b=e.target.closest('[data-act]'); if(!b) return;
|
||||
const act=b.dataset.act, id=b.dataset.id;
|
||||
if(act==='forget'){ const el=b.closest('.mem'); el.style.transition='.3s'; el.style.opacity='0'; el.style.transform='translateX(-12px)'; setTimeout(()=>el.remove(),300); toast('Forgotten '+id+' — removed from recall'); }
|
||||
else if(act==='confirm'){ const sb=b.closest('.stalebanner'); if(sb){ sb.outerHTML='<div class="corrected"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg><span>Confirmed still true · freshness reset</span></div>'; } toast('Confirmed '+id+' — freshness reset'); }
|
||||
else if(act==='edit'){ toast('Correcting '+id+' — opens an inline editor'); }
|
||||
});
|
||||
|
||||
const labels = { manage:'<b>Manage</b> — forget, correct, confirm; see confidence & freshness', why:'<b>Why-trace</b> — every action explains itself' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e=>{ const b=e.target.closest('button'); if(!b) return; [...seg.children].forEach(x=>x.classList.toggle('on',x===b)); document.querySelectorAll('.view').forEach(v=>v.classList.toggle('on', v.dataset.view===b.dataset.v)); document.getElementById('vlabel').innerHTML=labels[b.dataset.v]; document.querySelector('.stage').scrollTop=0; });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,260 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Onboarding</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 11px; border-radius: 7px; transition: .14s; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.stage { flex: 1; min-height: 0; position: relative; overflow: hidden; }
|
||||
.stage .comb { position: absolute; inset: 0; opacity: .5; pointer-events: none; }
|
||||
|
||||
/* progress */
|
||||
.prog { position: absolute; top: 18px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 8px; z-index: 5; }
|
||||
.prog .step { display:flex; align-items:center; gap: 8px; }
|
||||
.prog .pd { width: 26px; height: 4px; border-radius: 3px; background: var(--surface-3); transition:.3s; }
|
||||
.prog .pd.done { background: var(--honey); } .prog .pd.cur { background: var(--honey-bright); }
|
||||
|
||||
.screen { position: absolute; inset: 0; display: none; align-items: flex-start; justify-content: center; padding: 92px 32px 96px; overflow: auto; }
|
||||
.screen.on { display: flex; }
|
||||
.card { width: 100%; max-width: 600px; text-align: center; position: relative; }
|
||||
.eyebrow { font-family: var(--mono); font-size: 11px; letter-spacing:.14em; text-transform:uppercase; color: var(--honey); margin-bottom: 14px; }
|
||||
.card h1 { font-size: clamp(28px, 4vw, 40px); font-weight: 650; letter-spacing:-0.02em; line-height:1.06; margin: 0 0 14px; text-wrap:balance; }
|
||||
.card h1 em { font-style: normal; color: var(--honey); }
|
||||
.card .lede { font-size: 16px; color: var(--text-2); line-height: 1.55; margin: 0 auto 30px; max-width: 46ch; }
|
||||
.mk { width: 60px; height: 66px; margin: 0 auto 24px; display:grid; place-items:center; font-weight:800; font-size:24px; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); box-shadow: var(--honey-glow); }
|
||||
|
||||
.chips { display:flex; flex-wrap:wrap; gap: 10px; justify-content:center; margin-bottom: 16px; }
|
||||
.chip { font-size: 14px; font-weight: 550; padding: 10px 16px; border-radius: 999px; border:1px solid var(--line-strong); background: var(--surface); color: var(--text-2); cursor:pointer; transition:.14s; }
|
||||
.chip:hover { border-color: var(--honey-line); color: var(--text); }
|
||||
.chip.sel { background: var(--honey); color:#1a1407; border-color: var(--honey); }
|
||||
.flabel { font-size: 12.5px; color: var(--text-dim); margin: 22px 0 12px; font-family:var(--mono); letter-spacing:.08em; text-transform:uppercase; }
|
||||
.field { width:100%; max-width: 360px; margin: 0 auto 8px; padding: 12px 16px; border-radius: 11px; border:1px solid var(--line); background: var(--surface); color: var(--text); font-family:var(--sans); font-size:15px; outline:none; text-align:center; }
|
||||
.field:focus { border-color: var(--honey-line); }
|
||||
|
||||
/* import cards */
|
||||
.opts { display:grid; grid-template-columns: repeat(2,1fr); gap: 12px; max-width: 460px; margin: 0 auto; }
|
||||
.opt { padding: 18px; border-radius: var(--r-lg); border:1px solid var(--line-strong); background: var(--surface); cursor:pointer; transition:.15s; text-align:left; display:flex; align-items:center; gap:13px; }
|
||||
.opt:hover { border-color: var(--honey-line); } .opt.sel { border-color: var(--honey); background: var(--honey-wash); }
|
||||
.opt .oi { width:34px; height:38px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-weight:700; font-size:12px; color:var(--text); background:var(--surface-2); border:1px solid var(--line); }
|
||||
.opt b { font-size: 14px; font-weight: 650; display:block; } .opt small { font-size: 11.5px; color: var(--text-muted); }
|
||||
.reassure { margin-top: 18px; font-size: 12.5px; color: var(--text-dim); display:inline-flex; align-items:center; gap:8px; }
|
||||
.reassure svg { width:14px; height:14px; stroke: var(--healthy); fill:none; stroke-width:1.8; }
|
||||
|
||||
/* template cards */
|
||||
.tpls { display:grid; grid-template-columns: repeat(3,1fr); gap: 11px; max-width: 540px; margin: 0 auto; }
|
||||
.tpl { padding: 16px 12px; border-radius: var(--r); border:1px solid var(--line-strong); background: var(--surface); cursor:pointer; transition:.15s; }
|
||||
.tpl:hover { border-color: var(--honey-line); } .tpl.sel { border-color: var(--honey); background: var(--honey-wash); }
|
||||
.tpl .ti { width: 32px; height: 36px; margin: 0 auto 9px; display:grid; place-items:center; }
|
||||
.tpl .ti svg { width:18px; height:18px; stroke: var(--honey); fill:none; stroke-width:1.7; }
|
||||
.tpl b { font-size: 13px; font-weight: 600; display:block; } .tpl small { font-size: 10.5px; color: var(--text-dim); }
|
||||
|
||||
/* first task */
|
||||
.ask { display:flex; align-items:center; gap:10px; max-width: 480px; margin: 0 auto 16px; padding: 6px 6px 6px 18px; border-radius: 999px; border:1px solid var(--line); background: var(--surface); }
|
||||
.ask:focus-within { border-color: var(--honey-line); box-shadow: var(--honey-glow); }
|
||||
.ask input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--sans); font-size:15px; outline:none; text-align:left; }
|
||||
.ask .go { width:40px;height:40px;border-radius:999px;border:0;background:var(--honey);color:#1a1407;font-size:17px;cursor:pointer;flex:none; }
|
||||
.suggest { display:flex; flex-direction:column; gap:8px; max-width: 480px; margin: 0 auto; }
|
||||
.sg { text-align:left; padding: 11px 15px; border-radius: 10px; border:1px solid var(--line-soft); background: var(--surface); color: var(--text-2); font-size:13.5px; cursor:pointer; transition:.14s; }
|
||||
.sg:hover { border-color: var(--honey-line); color: var(--text); }
|
||||
|
||||
/* model gate */
|
||||
.mtabs { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); margin-bottom:20px; }
|
||||
.mtab { font-size:13px; font-weight:600; cursor:pointer; padding:8px 16px; border-radius:7px; color:var(--text-muted); }
|
||||
.mtab.sel { background:var(--honey); color:#1a1407; }
|
||||
.keyfield { display:flex; align-items:center; gap:10px; max-width:420px; margin:0 auto 8px; padding:6px 8px 6px 16px; border-radius:11px; border:1px solid var(--healthy); background:var(--surface); }
|
||||
.keyfield input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--mono); font-size:13.5px; outline:none; text-align:left; }
|
||||
.keyfield .valid { font-size:12px; font-weight:600; color:var(--healthy); white-space:nowrap; padding-right:6px; }
|
||||
.mpane.hidden { display:none; }
|
||||
|
||||
/* nav */
|
||||
.nav { position: absolute; bottom: 0; left:0; right:0; display:flex; align-items:center; justify-content:space-between; padding: 18px 32px; border-top: 1px solid var(--line-soft); background: color-mix(in srgb,var(--bg) 80%, transparent); backdrop-filter: blur(8px); }
|
||||
.nav .skip { font-size: 13px; color: var(--text-dim); cursor:pointer; } .nav .skip:hover { color: var(--text-2); }
|
||||
.nav .rgt { display:flex; gap: 10px; align-items:center; }
|
||||
.btn { font-family:var(--sans); font-size: 14px; font-weight: 650; padding: 11px 20px; border-radius: 11px; cursor:pointer; border:1px solid transparent; }
|
||||
.btn.back { background: transparent; color: var(--text-muted); } .btn.back:hover { color: var(--text); }
|
||||
.btn.next { background: var(--honey); color:#1a1407; } .btn.next:hover { background: var(--honey-bright); }
|
||||
@media (max-width: 620px){ .opts, .tpls { grid-template-columns: 1fr 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Onboarding · jump to step</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-s="0">1</button><button data-s="1">2</button><button data-s="2">3</button><button data-s="3">4</button><button data-s="4">5</button><button data-s="5">6</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Welcome</b> — first run, full-screen takeover</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="comb"></div>
|
||||
<div class="prog" id="prog"></div>
|
||||
|
||||
<!-- 1 welcome -->
|
||||
<div class="screen on" data-step="0">
|
||||
<div class="card">
|
||||
<div class="mk hex">W</div>
|
||||
<h1>Welcome to Waggle.<br>The workspace that <em>remembers.</em></h1>
|
||||
<p class="lede">In two minutes we'll set up a workspace that knows you and your work — so you never start from a blank box again. Everything stays on your machine.</p>
|
||||
<div class="chips"><span class="chip sel" onclick="next()">Let's set it up →</span></div>
|
||||
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Local-first · no account needed to start</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2 about you -->
|
||||
<div class="screen" data-step="1">
|
||||
<div class="card">
|
||||
<div class="eyebrow">Step 2 · about you</div>
|
||||
<h1>A little about <em>you.</em></h1>
|
||||
<p class="lede">This shapes how Waggle works for you — your personas, suggestions, and defaults. You can change any of it later.</p>
|
||||
<input class="field" placeholder="Your name" value="Mara">
|
||||
<div class="flabel">What do you do most?</div>
|
||||
<div class="chips" data-single>
|
||||
<span class="chip">Research</span><span class="chip sel">Strategy / exec</span><span class="chip">Engineering</span>
|
||||
<span class="chip">Writing</span><span class="chip">Sales</span><span class="chip">Legal</span><span class="chip">Finance</span>
|
||||
</div>
|
||||
<div class="flabel">Working...</div>
|
||||
<div class="chips" data-single>
|
||||
<span class="chip sel">Solo</span><span class="chip">Small team</span><span class="chip">Larger org</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3 give it a brain (model gate) -->
|
||||
<div class="screen" data-step="2">
|
||||
<div class="card">
|
||||
<div class="eyebrow">Step 3 · the one requirement</div>
|
||||
<h1>Give it a <em>brain.</em></h1>
|
||||
<p class="lede">Waggle is model-agnostic — but it needs at least one to think with. Bring an API key, or run a model locally. You can add more and set up failover anytime.</p>
|
||||
<div class="mtabs" id="mtabs"><span class="mtab sel" data-m="key">Use an API key</span><span class="mtab" data-m="local">Run it locally</span></div>
|
||||
|
||||
<div class="mpane" data-m="key">
|
||||
<div class="chips" data-single style="margin-bottom:14px"><span class="chip sel">Anthropic</span><span class="chip">OpenAI</span><span class="chip">Google</span><span class="chip">Groq</span></div>
|
||||
<div class="keyfield"><input placeholder="sk-ant-… paste your key" value="sk-ant-api03-••••••••••3a9f"><span class="valid">✓ valid</span></div>
|
||||
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Encrypted in your local vault — never shown to a model or sent anywhere</div>
|
||||
</div>
|
||||
|
||||
<div class="mpane hidden" data-m="local">
|
||||
<div class="opts" style="max-width:460px">
|
||||
<div class="opt sel"><div class="oi">QW</div><div><b>Qwen 2.5 7B</b><small>detected · Ollama · running</small></div></div>
|
||||
<div class="opt"><div class="oi">L3</div><div><b>Llama 3.2</b><small>pull · ~2 GB</small></div></div>
|
||||
</div>
|
||||
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></svg>100% on your machine — no key, no cloud, no cost</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4 import -->
|
||||
<div class="screen" data-step="3">
|
||||
<div class="card">
|
||||
<div class="eyebrow">Step 4 · bring your history</div>
|
||||
<h1>Start with what you <em>already have.</em></h1>
|
||||
<p class="lede">Import past conversations and Waggle learns you on day one. Or start fresh — it learns fast either way.</p>
|
||||
<div class="opts">
|
||||
<div class="opt sel"><div class="oi">CG</div><div><b>ChatGPT</b><small>export → import</small></div></div>
|
||||
<div class="opt"><div class="oi">Cl</div><div><b>Claude</b><small>export → import</small></div></div>
|
||||
<div class="opt"><div class="oi">Cu</div><div><b>Cursor</b><small>history</small></div></div>
|
||||
<div class="opt"><div class="oi">+</div><div><b>Start fresh</b><small>learns as you go</small></div></div>
|
||||
</div>
|
||||
<div class="reassure"><svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg>Imported on your machine — it never leaves</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5 template -->
|
||||
<div class="screen" data-step="4">
|
||||
<div class="card">
|
||||
<div class="eyebrow">Step 5 · first workspace</div>
|
||||
<h1>Pick a <em>starting point.</em></h1>
|
||||
<p class="lede">A template seeds the right persona, connectors, and a few starter prompts. One click and you're in.</p>
|
||||
<div class="tpls" id="tpls"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 6 first task -->
|
||||
<div class="screen" data-step="5">
|
||||
<div class="card">
|
||||
<div class="eyebrow">Step 6 · your first move</div>
|
||||
<h1>What should we <em>start with?</em></h1>
|
||||
<p class="lede">Type the first thing you'd like help with, or pick one — your workspace opens straight into it.</p>
|
||||
<div class="ask"><input placeholder="e.g. “Map our top 5 competitors and where we win”" value=""><button class="go">→</button></div>
|
||||
<div class="suggest" id="suggest"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
<span class="skip" id="skip">Skip setup</span>
|
||||
<div class="rgt">
|
||||
<button class="btn back" id="back" style="visibility:hidden">← Back</button>
|
||||
<button class="btn next" id="nextb">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const STEPS = 6;
|
||||
const labels = ['<b>Welcome</b> — first run, full-screen takeover','<b>About you</b> — role & team shape your defaults','<b>Give it a brain</b> — one model required (key or local)','<b>Import</b> — start from your history, locally','<b>Template</b> — seed persona + connectors','<b>First task</b> — open straight into the work'];
|
||||
let step = 0;
|
||||
|
||||
const tplData = [
|
||||
{ ic:'<path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/>', n:'Research', s:'analyst' },
|
||||
{ ic:'<path d="m12 3 2.5 6 6.5.5-5 4.2 1.6 6.3L12 16.8 6 20l1.6-6.3-5-4.2 6.5-.5z"/>', n:'Strategy', s:'consultant', sel:true },
|
||||
{ ic:'<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9z"/>', n:'Engineering', s:'coder' },
|
||||
{ ic:'<path d="m22 2-7 20-4-9-9-4Z"/>', n:'Sales', s:'sales-rep' },
|
||||
{ ic:'<path d="M4 6h16M4 12h12M4 18h8"/>', n:'Writing', s:'writer' },
|
||||
{ ic:'<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>', n:'Custom', s:'general' },
|
||||
];
|
||||
document.getElementById('tpls').innerHTML = tplData.map(t=>`<div class="tpl ${t.sel?'sel':''}"><div class="ti"><svg viewBox="0 0 24 24">${t.ic}</svg></div><b>${t.n}</b><small>${t.s}</small></div>`).join('');
|
||||
document.getElementById('suggest').innerHTML = ['Map our top 5 competitors and where we win','Draft the Q2 board narrative from this week\u2019s work','Summarize what changed in the market this month'].map(s=>`<div class="sg">${s}</div>`).join('');
|
||||
|
||||
// single-select chips & cards
|
||||
document.querySelectorAll('[data-single]').forEach(grp => grp.addEventListener('click', e => { const c=e.target.closest('.chip'); if(!c)return; grp.querySelectorAll('.chip').forEach(x=>x.classList.remove('sel')); c.classList.add('sel'); }));
|
||||
['opts','tpls'].forEach(id => { const el=document.getElementById(id)||document.querySelector('.'+id); });
|
||||
document.querySelector('.opts').addEventListener('click', e=>{const o=e.target.closest('.opt');if(!o)return;document.querySelectorAll('.opt').forEach(x=>x.classList.remove('sel'));o.classList.add('sel');});
|
||||
document.getElementById('tpls').addEventListener('click', e=>{const t=e.target.closest('.tpl');if(!t)return;document.querySelectorAll('.tpl').forEach(x=>x.classList.remove('sel'));t.classList.add('sel');});
|
||||
document.getElementById('suggest').addEventListener('click', e=>{const s=e.target.closest('.sg');if(s)document.querySelector('[data-step="5"] .ask input').value=s.textContent;});
|
||||
|
||||
// model step: tab switch + provider/local select
|
||||
const mtabs = document.getElementById('mtabs');
|
||||
mtabs.addEventListener('click', e => { const t=e.target.closest('.mtab'); if(!t)return; mtabs.querySelectorAll('.mtab').forEach(x=>x.classList.toggle('sel',x===t)); document.querySelectorAll('.mpane').forEach(p=>p.classList.toggle('hidden', p.dataset.m!==t.dataset.m)); });
|
||||
document.querySelectorAll('.mpane .opts').forEach(grp => grp.addEventListener('click', e=>{const o=e.target.closest('.opt');if(!o)return;grp.querySelectorAll('.opt').forEach(x=>x.classList.remove('sel'));o.classList.add('sel');}));
|
||||
|
||||
function renderProg(){ document.getElementById('prog').innerHTML = Array.from({length:STEPS},(_,i)=>`<span class="pd ${i<step?'done':i===step?'cur':''}"></span>`).join(''); }
|
||||
function go(s){
|
||||
step = Math.max(0, Math.min(STEPS-1, s));
|
||||
document.querySelectorAll('.screen').forEach(el => el.classList.toggle('on', +el.dataset.step===step));
|
||||
document.querySelectorAll('#seg button').forEach(b => b.classList.toggle('on', +b.dataset.s===step));
|
||||
document.getElementById('vlabel').innerHTML = labels[step];
|
||||
document.getElementById('back').style.visibility = step===0 ? 'hidden':'visible';
|
||||
document.getElementById('nextb').textContent = step===STEPS-1 ? 'Enter Waggle →' : 'Continue →';
|
||||
renderProg();
|
||||
}
|
||||
function next(){ go(step+1); }
|
||||
document.getElementById('nextb').onclick = () => { if(step===STEPS-1){ document.getElementById('nextb').textContent='Opening your workspace…'; } else next(); };
|
||||
document.getElementById('back').onclick = () => go(step-1);
|
||||
document.getElementById('skip').onclick = () => go(STEPS-1);
|
||||
document.getElementById('seg').addEventListener('click', e => { const b=e.target.closest('button'); if(b) go(+b.dataset.s); });
|
||||
go(0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,213 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Platform</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
|
||||
.controls { flex:none; display:flex; align-items:center; gap:14px; padding:11px 20px; border-bottom:1px solid var(--line-soft); background:color-mix(in srgb,var(--bg) 88%,transparent); backdrop-filter:blur(10px); z-index:30; }
|
||||
.controls .lab { font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-dim); }
|
||||
.seg { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.seg button { font-family:var(--sans); font-size:12px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:6px 11px; border-radius:7px; transition:.14s; white-space:nowrap; }
|
||||
.seg button.on { background:var(--honey); color:#1a1407; }
|
||||
.controls .vlabel { font-size:12.5px; color:var(--text-muted); } .controls .vlabel b { color:var(--text); font-weight:600; }
|
||||
.controls .right { margin-left:auto; display:flex; align-items:center; gap:10px; }
|
||||
.tbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--surface); color:var(--text-2); cursor:pointer; }
|
||||
.tbtn:hover { border-color:var(--honey-line); color:var(--honey); }
|
||||
.stage { flex:1; min-height:0; overflow:auto; position:relative; }
|
||||
.stage .comb { position:absolute; inset:0; opacity:.4; pointer-events:none; }
|
||||
.view { display:none; } .view.on { display:block; }
|
||||
.wrap { max-width:920px; margin:0 auto; padding:30px 32px 60px; position:relative; }
|
||||
.head { margin-bottom:24px; text-align:center; }
|
||||
.head .eyebrow { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--honey); margin-bottom:12px; }
|
||||
.head h1 { font-size:28px; font-weight:650; letter-spacing:-0.02em; margin:0 0 10px; } .head h1 em { font-style:normal; color:var(--honey); }
|
||||
.head p { font-size:15px; color:var(--text-muted); line-height:1.55; margin:0 auto; max-width:54ch; } .head p b { color:var(--text-2); }
|
||||
|
||||
/* desktop window mock */
|
||||
.winwrap { max-width:760px; margin:0 auto; }
|
||||
.ostabs { display:flex; gap:6px; justify-content:center; margin-bottom:16px; }
|
||||
.ostab { font-size:12.5px; font-weight:600; padding:7px 15px; border-radius:9px; border:1px solid var(--line-soft); background:var(--surface); color:var(--text-muted); cursor:pointer; display:inline-flex; align-items:center; gap:7px; }
|
||||
.ostab.on { border-color:var(--honey-line); background:var(--honey-wash); color:var(--honey); }
|
||||
.window { border-radius:12px; overflow:hidden; border:1px solid var(--line-strong); box-shadow:var(--shadow-lg); background:var(--bg-2); }
|
||||
.titlebar { height:38px; display:flex; align-items:center; gap:8px; padding:0 14px; background:var(--surface); border-bottom:1px solid var(--line-soft); }
|
||||
.titlebar.mac .lights { display:flex; gap:8px; } .titlebar .lights i { width:12px; height:12px; border-radius:999px; }
|
||||
.titlebar .lights .r { background:#ec6a5e; } .titlebar .lights .y { background:#f4bf4f; } .titlebar .lights .g { background:#61c554; }
|
||||
.titlebar .tt { flex:1; text-align:center; font-size:12px; color:var(--text-dim); font-family:var(--mono); }
|
||||
.titlebar.win { flex-direction:row-reverse; }
|
||||
.titlebar.win .lights { display:flex; gap:0; } .titlebar.win .lights i { width:30px; height:38px; border-radius:0; display:grid; place-items:center; color:var(--text-muted); font-size:12px; background:transparent; }
|
||||
.titlebar.win .lights i.x:hover { background:var(--risk); color:#fff; }
|
||||
.titlebar.mac .lights.winhide, .titlebar.win .lights.machide { display:none; }
|
||||
.winbody { display:flex; height:300px; }
|
||||
.wb-side { width:120px; flex:none; background:var(--bg-2); border-right:1px solid var(--line-soft); padding:14px 8px; }
|
||||
.wb-side .wi { display:flex; align-items:center; gap:8px; padding:7px 9px; border-radius:8px; font-size:12px; color:var(--text-2); margin-bottom:2px; } .wb-side .wi.on { background:var(--honey-wash); color:var(--text); } .wb-side .wi .d { width:13px; height:13px; border-radius:4px; background:var(--surface-3); } .wb-side .wi.on .d { background:var(--honey); }
|
||||
.wb-main { flex:1; padding:22px; background:var(--bg); }
|
||||
.wb-main .g { font-family:var(--mono); font-size:10px; color:var(--honey); letter-spacing:.08em; }
|
||||
.wb-main h3 { font-family:var(--sans); font-size:20px; font-weight:600; letter-spacing:-0.02em; margin:8px 0 14px; }
|
||||
.wb-main .ln { height:9px; border-radius:5px; background:var(--surface-2); margin-bottom:9px; } .wb-main .ln.s { width:60%; }
|
||||
|
||||
.specs { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-top:22px; }
|
||||
.spec { padding:16px; border-radius:var(--r); border:1px solid var(--line-soft); background:var(--surface); text-align:center; }
|
||||
.spec .sv { font-size:16px; font-weight:700; letter-spacing:-0.01em; } .spec .sl { font-size:11px; color:var(--text-muted); margin-top:5px; }
|
||||
|
||||
/* boot */
|
||||
.boot { min-height:440px; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; }
|
||||
.boot .mk { width:72px; height:80px; display:grid; place-items:center; font-weight:800; font-size:30px; color:#1a1407; background:linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); box-shadow:var(--honey-glow); margin-bottom:24px; animation:pulse 2.2s ease-in-out infinite; }
|
||||
@keyframes pulse { 0%,100%{ box-shadow:0 0 0 1px rgba(233,165,44,.25), 0 8px 30px -10px rgba(233,165,44,.35);} 50%{ box-shadow:0 0 0 1px rgba(233,165,44,.5), 0 8px 50px -6px rgba(233,165,44,.6);} }
|
||||
.boot h1 { font-size:24px; font-weight:600; letter-spacing:-0.02em; margin:0 0 8px; white-space:nowrap; }
|
||||
.boot .sub { font-family:var(--mono); font-size:12px; color:var(--text-dim); margin-bottom:26px; }
|
||||
.bootlist { display:grid; gap:8px; width:300px; text-align:left; }
|
||||
.bl { display:flex; align-items:center; gap:11px; font-size:13px; color:var(--text-2); }
|
||||
.bl .c { width:16px; height:16px; flex:none; } .bl .c svg { width:16px; height:16px; stroke:var(--healthy); fill:none; stroke-width:2.4; }
|
||||
.bl .spin { width:13px; height:13px; border-radius:999px; border:2px solid var(--honey); border-top-color:transparent; animation:spin .7s linear infinite; }
|
||||
@keyframes spin { to { transform:rotate(360deg); } }
|
||||
.bl.pending { color:var(--text-dim); }
|
||||
|
||||
/* roadmap */
|
||||
.channels { display:grid; gap:12px; }
|
||||
.ch { display:flex; align-items:center; gap:15px; padding:18px 20px; border-radius:var(--r-lg); border:1px solid var(--line-soft); background:var(--surface); }
|
||||
.ch.now { border-color:var(--honey-line); }
|
||||
.ch .ci { width:42px; height:46px; flex:none; display:grid; place-items:center; }
|
||||
.ch .ci svg { width:22px; height:22px; stroke:var(--honey); fill:none; stroke-width:1.7; }
|
||||
.ch .ct { flex:1; } .ch .ct b { font-size:15.5px; font-weight:650; } .ch .ct p { margin:3px 0 0; font-size:13px; color:var(--text-muted); }
|
||||
.ch .platforms { display:flex; gap:6px; margin-top:9px; } .ch .platforms span { font-family:var(--mono); font-size:10.5px; color:var(--text-dim); padding:3px 8px; border-radius:6px; border:1px solid var(--line-soft); }
|
||||
.ch .status { font-size:11.5px; font-weight:650; padding:6px 13px; border-radius:999px; white-space:nowrap; }
|
||||
.ch .status.now { color:var(--healthy); background:var(--healthy-wash); }
|
||||
.ch .status.next { color:var(--attention); background:var(--honey-wash); }
|
||||
.ch .status.beta { color:var(--work); background:var(--work-wash); }
|
||||
|
||||
/* 404 */
|
||||
.nf { min-height:420px; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; }
|
||||
.nf .big { font-family:var(--sans); font-size:88px; font-weight:750; letter-spacing:-0.04em; color:var(--honey); line-height:1; }
|
||||
.nf h1 { font-size:24px; font-weight:600; margin:12px 0 8px; }
|
||||
.nf p { font-size:14.5px; color:var(--text-muted); margin:0 0 24px; max-width:40ch; }
|
||||
.nf .acts { display:flex; gap:10px; } .nf .acts a { padding:11px 20px; border-radius:11px; font-size:14px; font-weight:650; text-decoration:none; cursor:pointer; } .nf .acts .go { background:var(--honey); color:#1a1407; } .nf .acts .ghost { background:var(--surface); color:var(--text-2); border:1px solid var(--line-strong); }
|
||||
|
||||
@media (max-width:820px){ .specs { grid-template-columns:1fr 1fr; } .winbody { height:auto; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Platform & roadmap</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="desktop">Desktop (now)</button>
|
||||
<button data-v="boot">Boot</button>
|
||||
<button data-v="roadmap">Coming next</button>
|
||||
<button data-v="nf">404</button>
|
||||
</div>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="comb"></div>
|
||||
|
||||
<!-- DESKTOP -->
|
||||
<div class="view on wrap" data-view="desktop">
|
||||
<div class="head">
|
||||
<div class="eyebrow">Ships now · Tauri</div>
|
||||
<h1>A real <em>desktop app.</em></h1>
|
||||
<p>Waggle ships as a native app for <b>Windows & macOS</b> — built on Tauri, so it's tiny, fast, and truly local. Your hive lives on your disk; the app just opens a window onto it.</p>
|
||||
</div>
|
||||
<div class="winwrap">
|
||||
<div class="ostabs" id="ostabs"><span class="ostab on" data-os="mac">macOS</span><span class="ostab" data-os="win">Windows</span></div>
|
||||
<div class="window">
|
||||
<div class="titlebar mac" id="titlebar">
|
||||
<div class="lights machide"><i class="r"></i><i class="y"></i><i class="g"></i></div>
|
||||
<div class="lights winhide"><i>―</i><i>▢</i><i class="x">✕</i></div>
|
||||
<div class="tt">Waggle</div>
|
||||
</div>
|
||||
<div class="winbody">
|
||||
<div class="wb-side"><div class="wi on"><span class="d"></span>Home</div><div class="wi"><span class="d"></span>Chat</div><div class="wi"><span class="d"></span>Memory</div><div class="wi"><span class="d"></span>Agents</div><div class="wi"><span class="d"></span>Library</div></div>
|
||||
<div class="wb-main"><div class="g">FRIDAY · 8:42</div><h3>Good morning, Mara.</h3><div class="ln"></div><div class="ln"></div><div class="ln s"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="specs">
|
||||
<div class="spec"><div class="sv">~12 MB</div><div class="sl">Install size</div></div>
|
||||
<div class="spec"><div class="sv">Local</div><div class="sl">Data on your disk</div></div>
|
||||
<div class="spec"><div class="sv">Auto-update</div><div class="sl">Signed & notarized</div></div>
|
||||
<div class="spec"><div class="sv">Win · Mac</div><div class="sl">Linux soon</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BOOT -->
|
||||
<div class="view wrap" data-view="boot">
|
||||
<div class="boot">
|
||||
<div class="mk hex">W</div>
|
||||
<h1>Warming the hive…</h1>
|
||||
<div class="sub">waggle · v1.0 · local</div>
|
||||
<div class="bootlist">
|
||||
<div class="bl"><span class="c"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Memory engine ready · 581 memories</div>
|
||||
<div class="bl"><span class="c"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Local model online · Qwen 2.5</div>
|
||||
<div class="bl"><span class="spin"></span>Loading workspaces… 8 found</div>
|
||||
<div class="bl pending"><span class="c"></span>Restoring your last session</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ROADMAP -->
|
||||
<div class="view wrap" data-view="roadmap">
|
||||
<div class="head">
|
||||
<div class="eyebrow">Where Waggle goes</div>
|
||||
<h1>One hive, <em>everywhere you work.</em></h1>
|
||||
<p>Your memory is the constant; the surfaces multiply. Desktop today — your phone and your messaging apps next.</p>
|
||||
</div>
|
||||
<div class="channels">
|
||||
<div class="ch now">
|
||||
<div class="ci hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M3 9h18M8 21h8"/></svg></div>
|
||||
<div class="ct"><b>Desktop app</b><p>The full hive — native, local, fast.</p><div class="platforms"><span>macOS</span><span>Windows</span><span>Linux soon</span></div></div>
|
||||
<span class="status now">● Available now</span>
|
||||
</div>
|
||||
<div class="ch">
|
||||
<div class="ci hex" style="background:var(--work-wash)"><svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7M14 3l6 6M14 3v6h6M9 13h2M9 17h6"/></svg></div>
|
||||
<div class="ct"><b>Browser extension</b><p>Capture context & recall memory anywhere on the web.</p><div class="platforms"><span>Chrome</span><span>Edge</span><span>Firefox</span></div></div>
|
||||
<span class="status beta">◐ In beta</span>
|
||||
</div>
|
||||
<div class="ch">
|
||||
<div class="ci hex" style="background:var(--honey-wash)"><svg viewBox="0 0 24 24"><path d="M21 11.5a8.4 8.4 0 0 1-9 8.4 8.6 8.6 0 0 1-3.8-.9L3 20l1.1-4.1A8.4 8.4 0 1 1 21 11.5z"/></svg></div>
|
||||
<div class="ct"><b>Messaging</b><p>Talk to your hive from where you already chat — same memory, same agents.</p><div class="platforms"><span>WhatsApp</span><span>Telegram</span><span>iMessage</span></div></div>
|
||||
<span class="status next">Coming next</span>
|
||||
</div>
|
||||
<div class="ch">
|
||||
<div class="ci hex" style="background:var(--intel-wash)"><svg viewBox="0 0 24 24"><rect x="7" y="3" width="10" height="18" rx="2"/><path d="M11 18h2"/></svg></div>
|
||||
<div class="ct"><b>Mobile</b><p>Your morning briefing and quick capture, in your pocket.</p><div class="platforms"><span>iOS</span><span>Android</span></div></div>
|
||||
<span class="status next">Coming next</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 404 -->
|
||||
<div class="view wrap" data-view="nf">
|
||||
<div class="nf">
|
||||
<div class="big">404</div>
|
||||
<h1>This cell of the hive is empty.</h1>
|
||||
<p>The page you're after doesn't exist — but your memory and workspaces are right where you left them.</p>
|
||||
<div class="acts"><a class="go" data-go="home">← Back to Home</a><a class="ghost">Search with ⌘K</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e=>{ const b=e.target.closest('button'); if(!b) return; [...seg.children].forEach(x=>x.classList.toggle('on',x===b)); document.querySelectorAll('.view').forEach(v=>v.classList.toggle('on', v.dataset.view===b.dataset.v)); document.querySelector('.stage').scrollTop=0; });
|
||||
|
||||
// os toggle
|
||||
document.getElementById('ostabs').addEventListener('click', e=>{
|
||||
const t=e.target.closest('.ostab'); if(!t) return;
|
||||
document.querySelectorAll('.ostab').forEach(x=>x.classList.toggle('on',x===t));
|
||||
const tb=document.getElementById('titlebar'); tb.className = 'titlebar '+t.dataset.os;
|
||||
});
|
||||
document.addEventListener('click', e=>{ const a=e.target.closest('[data-go=home]'); if(a){ try{ location.href='../Waggle Reimagined.html#home'; }catch(_){} } });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,280 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Settings</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.controls .exp { display:inline-flex; padding:3px; gap:3px; border-radius:9px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.controls .exp button { font-family:var(--sans); font-size:11.5px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:5px 10px; border-radius:6px; }
|
||||
.controls .exp button.on { background: var(--honey); color:#1a1407; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.app { flex: 1; min-height: 0; display: flex; }
|
||||
.rail { flex: none; width: 196px; border-right: 1px solid var(--line-soft); background: var(--bg-2); padding: 16px 10px; overflow:auto; }
|
||||
.rail .rh { font-family: var(--mono); font-size: 10px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); padding: 6px 11px 12px; }
|
||||
.ritem { display:flex; align-items:center; gap:11px; padding: 9px 11px; border-radius: 10px; cursor:pointer; color: var(--text-2); transition:.13s; font-size: 13.5px; font-weight: 550; position:relative; }
|
||||
.ritem:hover { background: var(--surface-2); color: var(--text); }
|
||||
.ritem.on { background: var(--honey-wash); color: var(--text); }
|
||||
.ritem.on::before { content:''; position:absolute; left:-10px; top:50%; transform:translateY(-50%); width:3px; height:17px; border-radius:3px; background: var(--honey); }
|
||||
.ritem svg { width:17px; height:17px; stroke: currentColor; fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; flex:none; }
|
||||
.ritem.on svg { stroke: var(--honey); }
|
||||
.ritem.adv { display:none; } body.everything .ritem.adv { display:flex; }
|
||||
.ritem .warn { margin-left:auto; width:7px; height:7px; border-radius:999px; background: var(--attention); }
|
||||
|
||||
.main { flex:1; min-width:0; display:flex; flex-direction:column; }
|
||||
.shead { flex:none; padding: 24px 30px 16px; border-bottom: 1px solid var(--line-soft); }
|
||||
.shead h1 { font-size: 21px; font-weight: 650; letter-spacing:-0.02em; margin: 0 0 4px; }
|
||||
.shead p { font-size: 13px; color: var(--text-muted); margin: 0; max-width: 64ch; line-height:1.5; }
|
||||
.bodyc { flex:1; min-height:0; overflow:auto; padding: 24px 30px 60px; }
|
||||
.panel { display:none; max-width: 680px; } .panel.on { display:block; }
|
||||
|
||||
.grp { font-family: var(--mono); font-size: 10.5px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); margin: 4px 0 14px; display:flex; align-items:center; gap:10px; }
|
||||
.grp:not(:first-child) { margin-top: 30px; }
|
||||
.grp::after { content:''; flex:1; height:1px; background: var(--line-soft); }
|
||||
|
||||
.card { border:1px solid var(--line-soft); background: var(--surface); border-radius: var(--r-lg); padding: 18px; margin-bottom: 12px; }
|
||||
.field-row { display:flex; align-items:center; justify-content:space-between; gap:16px; }
|
||||
.field-row .lt b { font-size: 14px; font-weight: 600; display:block; } .field-row .lt span { font-size: 12.5px; color: var(--text-muted); }
|
||||
.sw { width: 40px; height: 23px; border-radius: 999px; background: var(--surface-3); border:1px solid var(--line-strong); position:relative; cursor:pointer; transition:.16s; flex:none; }
|
||||
.sw::after { content:''; position:absolute; top:2px; left:2px; width:17px; height:17px; border-radius:999px; background: var(--text-muted); transition:.16s; }
|
||||
.sw.on { background: var(--honey); border-color: var(--honey); } .sw.on::after { left:19px; background:#1a1407; }
|
||||
|
||||
.seg2 { display:inline-flex; padding:3px; gap:3px; border-radius:10px; background:var(--surface-2); border:1px solid var(--line-soft); }
|
||||
.seg2 button { font-family:var(--sans); font-size:12.5px; font-weight:600; cursor:pointer; border:0; background:transparent; color:var(--text-muted); padding:7px 13px; border-radius:7px; }
|
||||
.seg2 button.on { background:var(--honey); color:#1a1407; }
|
||||
.theme-cards { display:flex; gap:12px; }
|
||||
.tc { flex:1; padding:16px; border-radius:var(--r); text-align:center; cursor:pointer; border:1px solid var(--line); }
|
||||
.tc.dk { background:#14110b; } .tc.lt { background:#f1e9d8; }
|
||||
.tc.sel { border:2px solid var(--honey); }
|
||||
.tc .lbl { font-size:12px; font-weight:600; margin-bottom:8px; } .tc.dk .lbl { color:#f6f1e4; } .tc.lt .lbl { color:#211b11; }
|
||||
.tc .dots { display:flex; gap:5px; justify-content:center; } .tc .dots i { width:11px; height:11px; border-radius:999px; }
|
||||
|
||||
/* ── MODELS: failover pilot chain ── */
|
||||
.pilot { border:1px solid var(--honey-line); border-radius: var(--r-xl); background: linear-gradient(160deg, var(--surface-2), var(--surface)); padding: 6px; box-shadow: var(--honey-glow); margin-bottom: 14px; }
|
||||
.pilot-h { display:flex; align-items:center; gap:10px; padding: 14px 16px 12px; }
|
||||
.pilot-h svg { width:18px; height:18px; stroke: var(--honey); fill:none; stroke-width:1.8; }
|
||||
.pilot-h b { font-size: 14px; font-weight:650; white-space:nowrap; } .pilot-h .sub { font-size:11.5px; color:var(--text-muted); margin-left:auto; font-family:var(--mono); white-space:nowrap; }
|
||||
.mslot { display:flex; align-items:center; gap:14px; padding: 14px 16px; border-radius: var(--r); background: var(--surface); border:1px solid var(--line-soft); margin: 4px; position:relative; }
|
||||
.mslot .tier { font-family:var(--mono); font-size:9.5px; letter-spacing:.1em; text-transform:uppercase; width: 64px; flex:none; }
|
||||
.mslot.primary .tier { color: var(--honey); } .mslot.fallback .tier { color: var(--work); } .mslot.budget .tier { color: var(--healthy); }
|
||||
.mslot .mlogo { width:32px; height:36px; flex:none; display:grid; place-items:center; font-family:var(--mono); font-size:11px; font-weight:700; color:var(--text-2); background:var(--surface-2); border:1px solid var(--line); }
|
||||
.mslot .mname { flex:1; min-width:0; } .mslot .mname b { font-size:14px; font-weight:600; } .mslot .mname span { font-size:12px; color:var(--text-muted); }
|
||||
.mslot .mstatus { font-size:11px; font-weight:600; padding:3px 9px; border-radius:999px; display:inline-flex; align-items:center; gap:5px; }
|
||||
.mslot .mstatus.ok { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.mslot .mstatus.local { color: var(--work); background: var(--work-wash); }
|
||||
.mslot .chg { font-size:12px; font-weight:600; color:var(--text-2); cursor:pointer; padding:6px 11px; border-radius:8px; border:1px solid var(--line-strong); background:var(--surface-2); }
|
||||
.mslot .chg:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.trigger { display:flex; align-items:center; gap:9px; padding: 5px 16px 5px 80px; font-size: 11.5px; color: var(--text-dim); font-family: var(--mono); }
|
||||
.trigger svg { width:13px; height:13px; stroke: var(--text-dim); fill:none; stroke-width:1.8; }
|
||||
.trigger b { color: var(--text-2); font-weight:500; }
|
||||
.budget-row { display:flex; align-items:center; gap:14px; padding: 14px 16px; margin-top:4px; border-top:1px dashed var(--line); }
|
||||
.budget-row .bl { flex:1; font-size:13px; } .budget-row .bl b { font-weight:600; }
|
||||
.budget-row input { width: 90px; padding:7px 11px; border-radius:8px; border:1px solid var(--line); background:var(--surface); color:var(--text); font-family:var(--mono); font-size:13px; text-align:right; outline:none; }
|
||||
.budget-row input:focus { border-color: var(--honey-line); }
|
||||
|
||||
.keyrow { display:flex; align-items:center; gap:12px; padding: 11px 14px; border-radius: var(--r); border:1px solid var(--line-soft); background: var(--surface); margin-bottom:8px; }
|
||||
.keyrow .kd { width:8px; height:8px; border-radius:999px; flex:none; } .keyrow .kd.on { background:var(--healthy); } .keyrow .kd.off { background:var(--text-dim); }
|
||||
.keyrow .kn { flex:1; font-size:13.5px; font-weight:550; } .keyrow .kn small { color:var(--text-dim); font-weight:400; margin-left:6px; }
|
||||
.keyrow .ks { font-size:11.5px; font-weight:600; } .keyrow .ks.on { color:var(--healthy); } .keyrow .ks.off { color:var(--attention); }
|
||||
.note2 { display:flex; gap:11px; padding:13px 15px; border-radius:var(--r); background: var(--honey-wash); border:1px solid var(--honey-line); margin-bottom:14px; }
|
||||
.note2 svg { width:17px; height:17px; stroke:var(--honey); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.note2 p { margin:0; font-size:12.5px; color:var(--text-2); line-height:1.55; } .note2 b { color:var(--text); }
|
||||
|
||||
.radio-row { display:flex; align-items:flex-start; gap:11px; padding: 12px 14px; border-radius: var(--r); border:1px solid var(--line-soft); background:var(--surface); cursor:pointer; margin-bottom:8px; }
|
||||
.radio-row.sel { border-color: var(--honey-line); background: var(--honey-wash); }
|
||||
.radio-row .rd { width:16px; height:16px; border-radius:999px; border:1px solid var(--line-strong); flex:none; margin-top:1px; } .radio-row.sel .rd { border-color: var(--honey); background: var(--honey); box-shadow: inset 0 0 0 3px var(--surface); }
|
||||
.radio-row b { font-size:13.5px; font-weight:600; } .radio-row p { margin:3px 0 0; font-size:12px; color:var(--text-muted); }
|
||||
|
||||
.plan-badge { display:inline-flex; align-items:center; gap:8px; font-size:13px; font-weight:650; padding:8px 14px; border-radius:999px; background: var(--honey-wash); color: var(--honey); border:1px solid var(--honey-line); }
|
||||
.btn { font-family:var(--sans); font-size:13px; font-weight:650; padding:9px 15px; border-radius:9px; cursor:pointer; border:1px solid transparent; display:inline-flex; align-items:center; gap:7px; }
|
||||
.btn.go { background:var(--honey); color:#1a1407; } .btn.ghost { background:var(--surface-2); color:var(--text-2); border-color:var(--line-strong); } .btn.danger { background:transparent; color:var(--risk); border-color:color-mix(in srgb,var(--risk) 35%,transparent); }
|
||||
.btn svg { width:14px; height:14px; stroke:currentColor; fill:none; stroke-width:2; }
|
||||
@media (max-width:800px){ .rail { width:60px; } .rail .rh, .ritem span.txt { display:none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Settings</span>
|
||||
<span class="vlabel" id="vlabel">Calm by default · depth when you ask for it</span>
|
||||
<div class="right">
|
||||
<span class="lab" style="margin-right:-4px">Show</span>
|
||||
<div class="exp" id="exp">
|
||||
<button data-e="essential" class="on">Essential</button>
|
||||
<button data-e="standard">Standard</button>
|
||||
<button data-e="everything">Everything</button>
|
||||
</div>
|
||||
<button class="tbtn" id="tbtn" title="Toggle theme">☾</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app">
|
||||
<nav class="rail" id="rail">
|
||||
<div class="rh">Settings</div>
|
||||
<div class="ritem" data-s="general"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M5 19l2-2M17 7l2-2"/></svg><span class="txt">General</span></div>
|
||||
<div class="ritem on" data-s="models"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="12" cy="12" r="3"/></svg><span class="txt">Models</span></div>
|
||||
<div class="ritem" data-s="perms"><svg viewBox="0 0 24 24"><path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg><span class="txt">Permissions</span></div>
|
||||
<div class="ritem" data-s="billing"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg><span class="txt">Plan</span></div>
|
||||
<div class="ritem" data-s="team"><svg viewBox="0 0 24 24"><circle cx="9" cy="8" r="3"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0M16 6a3 3 0 0 1 0 6"/></svg><span class="txt">Team</span></div>
|
||||
<div class="ritem" data-s="backup"><svg viewBox="0 0 24 24"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/></svg><span class="txt">Backup</span></div>
|
||||
<div class="ritem adv" data-s="advanced"><svg viewBox="0 0 24 24"><path d="M14 7l-1.5-1.5a2 2 0 0 0-3 0l-1 1M4 20l5-1 9-9-4-4-9 9z"/></svg><span class="txt">Advanced</span></div>
|
||||
</nav>
|
||||
|
||||
<div class="main">
|
||||
<div class="shead"><h1 id="sTitle">Models</h1><p id="sSub">Pick your intelligence and a failover chain — Waggle routes between them automatically.</p></div>
|
||||
<div class="bodyc" id="bodyc"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} document.querySelectorAll('.tc').forEach(c=>c.classList.toggle('sel', c.classList.contains(t==='dark'?'dk':'lt'))); }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const heads = {
|
||||
general:['General','The basics — appearance, language, and your data.'],
|
||||
models:['Models','Pick your intelligence and a failover chain — Waggle routes between them automatically.'],
|
||||
perms:['Permissions','How much your agents can do before they ask you.'],
|
||||
billing:['Plan','Your tier and what it unlocks.'],
|
||||
team:['Team','Connect a shared team server to sync workspaces.'],
|
||||
backup:['Backup & export','Your data is yours — take it anywhere, anytime.'],
|
||||
advanced:['Advanced','Developer mode, telemetry, and diagnostics.'],
|
||||
};
|
||||
|
||||
const panels = {
|
||||
models: () => `
|
||||
<div class="note2"><svg viewBox="0 0 24 24"><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg><p><b>Waggle needs at least one working model.</b> You have a key for Claude and a local model running — you're good. Everything below is optional tuning.</p></div>
|
||||
|
||||
<div class="pilot">
|
||||
<div class="pilot-h"><svg viewBox="0 0 24 24"><path d="M12 2 4 6v6c0 5 3.5 7.5 8 9 4.5-1.5 8-4 8-9V6z"/><path d="m9 12 2 2 4-4"/></svg><b>Model pilot</b><span class="sub">automatic failover</span></div>
|
||||
|
||||
<div class="mslot primary">
|
||||
<span class="tier">Primary</span>
|
||||
<div class="mlogo">CL</div>
|
||||
<div class="mname"><b>Claude Sonnet 4</b> <span>· best quality · ~$3/Mtok</span></div>
|
||||
<span class="mstatus ok">● key set</span>
|
||||
<span class="chg">Change</span>
|
||||
</div>
|
||||
<div class="trigger"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12l7 7 7-7"/></svg><span>if it <b>errors or is unavailable</b> →</span></div>
|
||||
<div class="mslot fallback">
|
||||
<span class="tier">Fallback</span>
|
||||
<div class="mlogo">GP</div>
|
||||
<div class="mname"><b>GPT-4o</b> <span>· reliable backup · ~$2.5/Mtok</span></div>
|
||||
<span class="mstatus ok">● key set</span>
|
||||
<span class="chg">Change</span>
|
||||
</div>
|
||||
<div class="trigger"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12l7 7 7-7"/></svg><span>when you <b>hit your daily budget</b> →</span></div>
|
||||
<div class="mslot budget">
|
||||
<span class="tier">Budget</span>
|
||||
<div class="mlogo">QW</div>
|
||||
<div class="mname"><b>Qwen 2.5 · local</b> <span>· free · runs on this Mac</span></div>
|
||||
<span class="mstatus local">● running</span>
|
||||
<span class="chg">Change</span>
|
||||
</div>
|
||||
|
||||
<div class="budget-row">
|
||||
<div class="bl"><b>Daily budget</b> · switch to the budget model at 80%</div>
|
||||
<input value="50" type="number"><span style="color:var(--text-dim);font-family:var(--mono);font-size:13px">USD</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grp">Provider keys · managed in the Vault</div>
|
||||
<div class="note2" style="background:var(--bg-2);border-color:var(--line-soft)"><svg viewBox="0 0 24 24" style="stroke:var(--text-muted)"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg><p>Keys are encrypted on this machine. This list is read-only — add or rotate keys in the <b>Vault</b>.</p></div>
|
||||
<div class="keyrow"><span class="kd on"></span><span class="kn">Anthropic <small>Claude</small></span><span class="ks on">✓ key set</span></div>
|
||||
<div class="keyrow"><span class="kd on"></span><span class="kn">OpenAI <small>GPT</small></span><span class="ks on">✓ key set</span></div>
|
||||
<div class="keyrow"><span class="kd off"></span><span class="kn">Google <small>Gemini</small></span><span class="ks off">add in Vault</span></div>
|
||||
|
||||
<div class="grp">Local models · on this machine</div>
|
||||
<div class="keyrow"><span class="kd on"></span><span class="kn">Qwen 2.5 7B <small>via Ollama</small></span><span class="ks on">● running</span></div>
|
||||
<div class="keyrow"><span class="kd off"></span><span class="kn">Llama 3.2 <small>via Ollama</small></span><span class="ks off">pull to use</span></div>`,
|
||||
|
||||
general: () => `
|
||||
<div class="grp">Appearance</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Theme</b><span>Match the hive to your eyes.</span></div></div>
|
||||
<div class="theme-cards" style="margin-top:14px" id="themeCards">
|
||||
<div class="tc dk" data-t="dark"><div class="lbl">Dark</div><div class="dots"><i style="background:#14110b;border:1px solid #38301f"></i><i style="background:#e9a52c"></i><i style="background:#272117"></i></div></div>
|
||||
<div class="tc lt" data-t="light"><div class="lbl">Light</div><div class="dots"><i style="background:#fffdf8;border:1px solid #e4d8be"></i><i style="background:#b57d12"></i><i style="background:#efe6d2"></i></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Language</b><span>Interface language.</span></div><div class="seg2"><button class="on">English</button><button>Deutsch</button><button>+</button></div></div></div>
|
||||
|
||||
<div class="grp">Your data</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Local-first storage</b><span>Memory & files stay on this machine unless you share a workspace.</span></div><span class="plan-badge" style="font-size:11.5px">⬡ On · always</span></div></div>
|
||||
<div class="card" style="border-color:color-mix(in srgb,var(--risk) 25%,var(--line-soft))"><div class="field-row"><div class="lt"><b>Erase all data</b><span>Schedule a complete, unrecoverable wipe at next launch.</span></div><button class="btn danger"><svg viewBox="0 0 24 24"><path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13"/></svg>Erase…</button></div></div>`,
|
||||
|
||||
perms: () => `
|
||||
<div class="grp">Default approval level <span style="color:var(--text-dim);text-transform:none;letter-spacing:0">— new chats inherit this; each window can override</span></div>
|
||||
<div class="radio-row"><div class="rd"></div><div><b>Ask every time</b><p>Approve every write, edit, and mutating tool call. Safest.</p></div></div>
|
||||
<div class="radio-row sel"><div class="rd"></div><div><b>Ask only for risky things</b><p>Auto-pass routine writes & edits; still gate git push, installs, and anything that leaves your machine. Recommended.</p></div></div>
|
||||
<div class="radio-row"><div class="rd"></div><div><b>Never ask</b><p>Auto-pass everything except a hardcoded critical blacklist. Fastest, for trusted flows.</p></div></div>
|
||||
<div class="grp">Always require approval for</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b class="mono" style="font-family:var(--mono);font-size:12.5px">git push</b></div><span class="ks off" style="color:var(--text-dim);font-size:12px;cursor:pointer">Remove</span></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b class="mono" style="font-family:var(--mono);font-size:12.5px">anything → external system</b></div><span class="ks off" style="color:var(--text-dim);font-size:12px;cursor:pointer">Remove</span></div></div>`,
|
||||
|
||||
billing: () => `
|
||||
<div class="card" style="border-color:var(--honey-line)"><div class="field-row"><div class="lt"><b>Pro · trial</b><span>11 days left · $19/mo after · unlimited workspaces, marketplace, all connectors</span></div><span class="plan-badge">PRO</span></div></div>
|
||||
<div class="grp">Switch plan</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Teams</b><span>$49/seat · shared memory, WaggleDance, SSO & governance</span></div><button class="btn ghost">Upgrade →</button></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>KVARK · sovereign</b><span>On your own infrastructure, full audit trail. By Egzakta Group.</span></div><button class="btn ghost">Talk to sales →</button></div></div>
|
||||
<div style="margin-top:12px"><button class="btn ghost">Manage subscription</button></div>`,
|
||||
|
||||
team: () => `
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Status</b><span>Not connected to a team server.</span></div><span class="ks off" style="color:var(--text-dim)">● Disconnected</span></div></div>
|
||||
<div class="note2"><svg viewBox="0 0 24 24"><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg><p>Connecting to a team server <b>shares the workspaces you choose</b>. Only connect to a server you trust.</p></div>
|
||||
<div class="card"><div class="lt" style="margin-bottom:10px"><b>Team server URL</b></div><input style="width:100%;padding:10px 13px;border-radius:9px;border:1px solid var(--line);background:var(--surface);color:var(--text);font-family:var(--sans);font-size:14px;outline:none" placeholder="https://team.waggle.ai"></div>
|
||||
<button class="btn go">Connect</button>`,
|
||||
|
||||
backup: () => `
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Export everything</b><span>All workspaces, sessions, and memory as a zip.</span></div><button class="btn ghost"><svg viewBox="0 0 24 24"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/></svg>Export</button></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Import</b><span>From a Waggle export, or ChatGPT / Claude / Cursor history.</span></div><button class="btn ghost"><svg viewBox="0 0 24 24"><path d="M12 21V9m0 0 4 4m-4-4-4 4M5 3h14"/></svg>Import</button></div></div>
|
||||
<div class="grp">Encrypted backup</div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>AES-256 backup</b><span>Restore on any machine with the same vault key.</span></div><div style="display:flex;gap:8px"><button class="btn go">Create</button><button class="btn ghost">Restore</button></div></div></div>`,
|
||||
|
||||
advanced: () => `
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Developer mode</b><span>Show raw events, tool I/O, and the prompt inspector.</span></div><div class="sw" onclick="this.classList.toggle('on')"></div></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Anonymous telemetry</b><span>Local-only usage counters — never leaves the machine. 0 events.</span></div><div class="sw" onclick="this.classList.toggle('on')"></div></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Prompt shape</b><span>GEPA-evolved prompt variant for the agent runtime.</span></div><div class="seg2"><button class="on">Auto</button><button>Concise</button><button>Thorough</button></div></div></div>
|
||||
<div class="card"><div class="field-row"><div class="lt"><b>Debug logging</b><span>Verbose logs to the local console.</span></div><div class="sw" onclick="this.classList.toggle('on')"></div></div></div>`,
|
||||
};
|
||||
|
||||
function show(s){
|
||||
document.querySelectorAll('.ritem').forEach(r => r.classList.toggle('on', r.dataset.s===s));
|
||||
document.getElementById('sTitle').textContent = heads[s][0];
|
||||
document.getElementById('sSub').textContent = heads[s][1];
|
||||
document.getElementById('bodyc').innerHTML = panels[s]();
|
||||
document.getElementById('bodyc').scrollTop = 0;
|
||||
if(s==='general'){ const cur = root.getAttribute('data-theme'); document.querySelectorAll('.tc').forEach(c=>c.classList.toggle('sel', c.dataset.t===cur)); document.getElementById('themeCards').addEventListener('click', e=>{const c=e.target.closest('.tc'); if(c) setTheme(c.dataset.t);}); }
|
||||
}
|
||||
document.getElementById('rail').addEventListener('click', e => { const r=e.target.closest('.ritem'); if(r) show(r.dataset.s); });
|
||||
|
||||
/* radio rows + key/perms interactions */
|
||||
document.getElementById('bodyc').addEventListener('click', e => {
|
||||
const r = e.target.closest('.radio-row'); if(r){ r.parentElement.querySelectorAll('.radio-row').forEach(x=>x.classList.remove('sel')); r.classList.add('sel'); }
|
||||
});
|
||||
|
||||
/* experience level (progressive disclosure) */
|
||||
const labels = { essential:'Calm by default · the essentials only', standard:'Standard · full workspace tools', everything:'Everything · all controls visible' };
|
||||
document.getElementById('exp').addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...e.currentTarget.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.body.classList.toggle('everything', b.dataset.e==='everything');
|
||||
document.getElementById('vlabel').textContent = labels[b.dataset.e];
|
||||
if(b.dataset.e!=='everything' && document.querySelector('.ritem[data-s=advanced]').classList.contains('on')) show('models');
|
||||
});
|
||||
|
||||
show('models');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
225
docs/design_handoff_waggle_app/design-files/screens/storage.html
Normal file
@@ -0,0 +1,225 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Storage & files</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
|
||||
/* ── A: storage map ── */
|
||||
.wrap { max-width: 940px; margin: 0 auto; padding: 30px 32px 70px; }
|
||||
.head h1 { font-size: 26px; font-weight: 650; letter-spacing:-0.02em; margin: 0 0 8px; }
|
||||
.head .crumbs { font-family: var(--mono); font-size: 11px; color: var(--text-dim); margin-bottom: 12px; } .head .crumbs b { color: var(--text-2); font-weight: 500; }
|
||||
.head p { font-size: 15px; color: var(--text-muted); line-height: 1.55; margin: 0; max-width: 62ch; }
|
||||
|
||||
.liveloc { margin-top: 24px; border: 1px solid var(--honey-line); border-radius: var(--r-xl); background: linear-gradient(150deg, var(--surface-2), var(--surface)); padding: 24px; box-shadow: var(--honey-glow); }
|
||||
.liveloc .top { display: flex; align-items: center; gap: 13px; margin-bottom: 18px; }
|
||||
.liveloc .wm { width: 40px; height: 44px; flex:none; display:grid; place-items:center; font-weight:800; font-size:15px; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.liveloc .top b { font-size: 16px; font-weight: 650; } .liveloc .top .sub { font-size: 12px; color: var(--text-muted); }
|
||||
.liveloc .top .pillk { margin-left:auto; font-size: 12px; font-weight: 600; color: var(--honey); background: var(--honey-wash); border: 1px solid var(--honey-line); padding: 6px 12px; border-radius: 999px; }
|
||||
.tree { font-family: var(--mono); font-size: 12.5px; background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: var(--r); padding: 14px 16px; }
|
||||
.tline { display: flex; align-items: baseline; gap: 12px; line-height: 1.95; }
|
||||
.tline .nm { flex: 1; }
|
||||
.tree .dir { color: var(--honey); } .tree .f .nm { color: var(--text-2); } .tree .note { color: var(--text-dim); }
|
||||
.tree .sz { color: var(--text-dim); white-space: nowrap; }
|
||||
|
||||
.sec-h { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin: 30px 0 14px; display:flex; align-items:center; gap:10px; }
|
||||
.sec-h::after { content:''; flex:1; height:1px; background: var(--line-soft); }
|
||||
|
||||
.types { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
|
||||
.type { border: 1px solid var(--line-soft); background: var(--surface); border-radius: var(--r-lg); padding: 20px; position: relative; }
|
||||
.type.active { border-color: var(--honey-line); }
|
||||
.type .ic { width: 36px; height: 40px; display:grid; place-items:center; margin-bottom: 12px; }
|
||||
.type .ic svg { width: 19px; height: 19px; fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
|
||||
.type.virtual .ic svg { stroke: var(--intel); } .type.local .ic svg { stroke: var(--honey); } .type.team .ic svg { stroke: var(--healthy); }
|
||||
.type h3 { font-size: 16px; font-weight: 650; letter-spacing:-0.01em; margin: 0 0 4px; }
|
||||
.type .where { font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); margin-bottom: 10px; }
|
||||
.type p { font-size: 13px; color: var(--text-muted); line-height: 1.55; margin: 0 0 12px; }
|
||||
.type .priv { font-size: 11.5px; font-weight: 600; display:inline-flex; align-items:center; gap:6px; padding: 4px 10px; border-radius: 999px; }
|
||||
.type.virtual .priv { color: var(--intel); background: var(--intel-wash); }
|
||||
.type.local .priv { color: var(--honey); background: var(--honey-wash); }
|
||||
.type.team .priv { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.type .cur { position:absolute; top:16px; right:16px; font-family: var(--mono); font-size: 9.5px; letter-spacing:.1em; text-transform:uppercase; color: var(--honey); }
|
||||
|
||||
.reassure { margin-top: 22px; display:flex; gap: 13px; align-items: flex-start; padding: 16px 18px; border-radius: var(--r-lg); background: var(--bg-2); border: 1px solid var(--line-soft); }
|
||||
.reassure svg { width: 20px; height: 20px; stroke: var(--healthy); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.reassure p { margin: 0; font-size: 13.5px; color: var(--text-muted); line-height: 1.6; } .reassure b { color: var(--text); }
|
||||
|
||||
/* ── B: file browser ── */
|
||||
.files { display: flex; height: 100%; }
|
||||
.ftree { flex: none; width: 220px; border-right: 1px solid var(--line-soft); background: var(--bg-2); padding: 16px 10px; overflow:auto; }
|
||||
.ftree .fh { font-family: var(--mono); font-size: 10px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); padding: 6px 10px 10px; }
|
||||
.ftree .row { display:flex; align-items:center; gap:9px; padding: 7px 10px; border-radius: 8px; font-size: 13px; color: var(--text-2); cursor:pointer; }
|
||||
.ftree .row:hover { background: var(--surface-2); } .ftree .row.on { background: var(--honey-wash); color: var(--text); }
|
||||
.ftree .row.in { padding-left: 26px; }
|
||||
.ftree .row svg { width: 15px; height: 15px; stroke: var(--honey); fill: none; stroke-width:1.7; flex:none; }
|
||||
.fmain { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
||||
.fbar { flex:none; display:flex; align-items:center; gap:12px; padding: 13px 20px; border-bottom: 1px solid var(--line-soft); }
|
||||
.fbar .bc { font-size: 13px; color: var(--text-muted); } .fbar .bc b { color: var(--text); font-weight:600; }
|
||||
.fbar .acts { margin-left:auto; display:flex; gap:8px; }
|
||||
.fbar .ab { font-size: 12px; font-weight:600; color: var(--text-2); padding: 7px 12px; border-radius: 8px; border:1px solid var(--line-strong); background: var(--surface); cursor:pointer; display:inline-flex; align-items:center; gap:6px; }
|
||||
.fbar .ab:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.flist { flex:1; min-height:0; overflow:auto; padding: 8px 12px; }
|
||||
.ftab { width:100%; border-collapse: collapse; }
|
||||
.ftab th { text-align:left; font-family: var(--mono); font-size: 10px; letter-spacing:.06em; text-transform:uppercase; color: var(--text-dim); font-weight: 600; padding: 8px 10px; border-bottom: 1px solid var(--line-soft); }
|
||||
.ftab th.r, .ftab td.r { text-align: right; }
|
||||
.ftab td { padding: 10px; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; color: var(--text-2); }
|
||||
.ftab tr { cursor: pointer; } .ftab tbody tr:hover td { background: var(--surface-2); }
|
||||
.ftab tr.sel td { background: var(--honey-wash); }
|
||||
.ftab .nmc { display:flex; align-items:center; gap:11px; } .ftab .nmc b { color: var(--text); font-weight: 550; }
|
||||
.ftab .fi { width: 28px; height: 30px; flex:none; display:grid; place-items:center; font-family: var(--mono); font-size: 9px; font-weight:700; border-radius: 6px; }
|
||||
.ftab .prov { font-family: var(--mono); font-size: 10.5px; color: var(--intel); }
|
||||
.fstatus { flex:none; display:flex; align-items:center; justify-content:space-between; padding: 9px 20px; border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--text-muted); }
|
||||
.fstatus .loc { display:inline-flex; align-items:center; gap:8px; font-family: var(--mono); font-size: 11px; }
|
||||
.fstatus .loc .dot { background: var(--honey); }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width:820px){ .types { grid-template-columns: 1fr; } .ftree { width: 160px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Storage · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Where it lives</button>
|
||||
<button data-v="b">B · Files</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Where it lives</b> — the workspace, made legible</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<!-- ════ A — STORAGE MAP ════ -->
|
||||
<div class="wrap view" id="view-a">
|
||||
<div class="head">
|
||||
<div class="crumbs">Competitive Intelligence <span>›</span> <b>Storage</b></div>
|
||||
<h1>Where this workspace lives</h1>
|
||||
<p>A workspace is one place on disk: its memory, its files, its artifacts. Waggle shows you exactly where — and keeps it local unless you choose to share.</p>
|
||||
</div>
|
||||
|
||||
<div class="liveloc">
|
||||
<div class="top">
|
||||
<div class="wm hex">C</div>
|
||||
<div><b>Competitive Intelligence</b><div class="sub">Local workspace · on this Mac</div></div>
|
||||
<span class="pillk">⬡ Local · private</span>
|
||||
</div>
|
||||
<div class="tree">
|
||||
<div class="tline note"><span class="nm">~/Waggle/workspaces/</span></div>
|
||||
<div class="tline dir"><span class="nm" style="padding-left:1.4em">competitive-intelligence/</span></div>
|
||||
<div class="tline f"><span class="nm" style="padding-left:2.8em">hive.mind</span><span class="sz">3.2 MB · 142 memories</span></div>
|
||||
<div class="tline f"><span class="nm" style="padding-left:2.8em">files/</span><span class="sz">12 files · 4.1 MB</span></div>
|
||||
<div class="tline f"><span class="nm" style="padding-left:2.8em">artifacts/</span><span class="sz">7 items</span></div>
|
||||
<div class="tline f"><span class="nm" style="padding-left:2.8em">workspace.json</span><span class="sz">config</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-h">Three ways a workspace can live</div>
|
||||
<div class="types">
|
||||
<div class="type virtual">
|
||||
<div class="ic"><svg viewBox="0 0 24 24"><path d="M4 7c0-1.5 3.6-2.5 8-2.5s8 1 8 2.5-3.6 2.5-8 2.5-8-1-8-2.5z"/><path d="M4 7v10c0 1.5 3.6 2.5 8 2.5s8-1 8-2.5V7"/></svg></div>
|
||||
<h3>Virtual</h3>
|
||||
<div class="where">managed by Waggle</div>
|
||||
<p>Files Waggle keeps for you inside the app — no folder to manage. Perfect for quick, throwaway work.</p>
|
||||
<span class="priv">⬡ Only you · session</span>
|
||||
</div>
|
||||
<div class="type local active">
|
||||
<span class="cur">this one</span>
|
||||
<div class="ic"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M3 9h18M8 21h8"/></svg></div>
|
||||
<h3>Local</h3>
|
||||
<div class="where">a folder on your machine</div>
|
||||
<p>Bound to a real folder you can open in Finder. Your agents read and write the same files you do.</p>
|
||||
<span class="priv">⬡ Only you · on disk</span>
|
||||
</div>
|
||||
<div class="type team">
|
||||
<div class="ic"><svg viewBox="0 0 24 24"><circle cx="9" cy="8" r="3"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0M16 6a3 3 0 0 1 0 6M21 20a5 5 0 0 0-4-4.9"/></svg></div>
|
||||
<h3>Team</h3>
|
||||
<div class="where">shared, synced</div>
|
||||
<p>A shared memory + file space for a team — same workspace, role-based access, synced across seats.</p>
|
||||
<span class="priv">⬡ Shared with team</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reassure">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/><path d="M9 12l2 2 4-4"/></svg>
|
||||
<p><b>Local-first, always.</b> Memory and files for Virtual and Local workspaces never leave this machine — there's nothing for anyone to leak, subpoena, or sell. Switch a workspace to Team only when you mean to share it, and you can export or delete any workspace, whole, at any time.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════ B — FILES ════ -->
|
||||
<div class="files view hidden" id="view-b">
|
||||
<aside class="ftree">
|
||||
<div class="fh">Competitive Intel</div>
|
||||
<div class="row on"><svg viewBox="0 0 24 24"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>Root</div>
|
||||
<div class="row in"><svg viewBox="0 0 24 24"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>research</div>
|
||||
<div class="row in"><svg viewBox="0 0 24 24"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>exports</div>
|
||||
</aside>
|
||||
<div class="fmain">
|
||||
<div class="fbar">
|
||||
<span class="bc">Root <span style="color:var(--text-dim)">/</span> <b>Competitive Intelligence</b></span>
|
||||
<div class="acts">
|
||||
<span class="ab"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>New folder</span>
|
||||
<span class="ab"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"/></svg>Upload</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flist">
|
||||
<table class="ftab">
|
||||
<thead><tr><th>Name</th><th>Source</th><th class="r">Size</th><th class="r">Modified</th></tr></thead>
|
||||
<tbody id="fbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="fstatus">
|
||||
<span>12 items · 4.1 MB</span>
|
||||
<span class="loc"><span class="dot"></span>Local · private · ~/Waggle/workspaces/competitive-intelligence/files</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const files = [
|
||||
{ ext:'DIR', c:'var(--honey)', n:'research', dir:true, src:'—', size:'—', when:'2d ago' },
|
||||
{ ext:'DIR', c:'var(--honey)', n:'exports', dir:true, src:'—', size:'—', when:'2h ago' },
|
||||
{ ext:'MD', c:'var(--work)', n:'teardown.md', src:'made by Waggle', size:'48 KB', when:'2h ago' },
|
||||
{ ext:'XLS', c:'var(--healthy)', n:'pricing-landscape.xlsx', src:'made by Waggle', size:'126 KB', when:'2h ago' },
|
||||
{ ext:'PDF', c:'var(--risk)', n:'mem0-teardown.pdf', src:'you uploaded', size:'1.4 MB', when:'1d ago' },
|
||||
{ ext:'PDF', c:'var(--risk)', n:'letta-pricing.pdf', src:'you uploaded', size:'880 KB', when:'1d ago' },
|
||||
{ ext:'MD', c:'var(--work)', n:'board-brief.md', src:'made by Claude Code', size:'22 KB', when:'18m ago' },
|
||||
];
|
||||
document.getElementById('fbody').innerHTML = files.map(f=>`
|
||||
<tr><td><div class="nmc"><span class="fi" style="background:color-mix(in srgb,${f.c} 18%,transparent);color:${f.c}">${f.dir?'<svg width=14 height=14 viewBox="0 0 24 24" fill=none stroke="'+f.c+'" stroke-width=1.8><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>':f.ext}</span><b>${f.n}</b></div></td><td>${f.src==='—'?'<span style="color:var(--text-dim)">—</span>':`<span class="prov">⬡ ${f.src}</span>`}</td><td class="r" style="color:var(--text-dim)">${f.size}</td><td class="r" style="color:var(--text-dim)">${f.when}</td></tr>`).join('');
|
||||
document.querySelectorAll('#fbody tr').forEach(tr => tr.onclick = () => { document.querySelectorAll('#fbody tr').forEach(x=>x.classList.remove('sel')); tr.classList.add('sel'); });
|
||||
|
||||
const labels = { a:'<b>Where it lives</b> — the workspace, made legible', b:'<b>Files</b> — a clean browser, with provenance' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.getElementById('view-a').classList.toggle('hidden', b.dataset.v!=='a');
|
||||
document.getElementById('view-b').classList.toggle('hidden', b.dataset.v!=='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,217 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Power surfaces</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.controls .hint { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.app { flex: 1; min-height: 0; display: flex; }
|
||||
/* rail */
|
||||
.rail { flex: none; width: 200px; border-right: 1px solid var(--line-soft); background: var(--bg-2); padding: 16px 10px; }
|
||||
.rail .rh { font-family: var(--mono); font-size: 10px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); padding: 6px 11px 12px; }
|
||||
.ritem { display:flex; align-items:center; gap:11px; padding: 9px 11px; border-radius: 10px; cursor:pointer; color: var(--text-2); transition:.13s; font-size: 13.5px; font-weight: 550; position: relative; }
|
||||
.ritem:hover { background: var(--surface-2); color: var(--text); }
|
||||
.ritem.on { background: var(--honey-wash); color: var(--text); }
|
||||
.ritem.on::before { content:''; position:absolute; left:-10px; top:50%; transform:translateY(-50%); width:3px; height:17px; border-radius:3px; background: var(--honey); }
|
||||
.ritem svg { width:17px; height:17px; stroke: currentColor; fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; flex:none; }
|
||||
.ritem.on svg { stroke: var(--honey); }
|
||||
.ritem .ct { margin-left:auto; font-family: var(--mono); font-size: 10px; color: var(--text-dim); }
|
||||
.ritem .ct.warn { color: var(--attention); }
|
||||
|
||||
/* main */
|
||||
.main { flex:1; min-width:0; display:flex; flex-direction:column; }
|
||||
.shead { flex:none; display:flex; align-items:flex-start; gap:16px; padding: 26px 30px 18px; border-bottom: 1px solid var(--line-soft); }
|
||||
.shead h1 { font-size: 22px; font-weight: 650; letter-spacing:-0.02em; margin: 0 0 5px; }
|
||||
.shead p { font-size: 13.5px; color: var(--text-muted); margin: 0; max-width: 60ch; line-height:1.5; }
|
||||
.shead .pa { margin-left:auto; font-size: 12.5px; font-weight: 650; padding: 9px 15px; border-radius: 9px; background: var(--honey); color:#1a1407; cursor:pointer; white-space:nowrap; border:0; display:inline-flex; align-items:center; gap:7px; }
|
||||
.shead .pa:hover { background: var(--honey-bright); }
|
||||
.body { flex:1; min-height:0; overflow:auto; padding: 22px 30px 50px; }
|
||||
.panel { display:none; } .panel.on { display:block; }
|
||||
.grp { font-family: var(--mono); font-size: 10.5px; letter-spacing:.12em; text-transform:uppercase; color: var(--text-dim); margin: 4px 0 12px; display:flex; align-items:center; gap:10px; }
|
||||
.grp:not(:first-child) { margin-top: 26px; }
|
||||
.grp::after { content:''; flex:1; height:1px; background: var(--line-soft); }
|
||||
|
||||
.rows { display:grid; gap: 9px; }
|
||||
.rc { display:flex; align-items:center; gap:14px; padding: 14px 16px; border-radius: var(--r); border: 1px solid var(--line-soft); background: var(--surface); transition:.14s; }
|
||||
.rc:hover { border-color: var(--line-strong); }
|
||||
.rc .ri { width: 34px; height: 38px; flex:none; display:grid; place-items:center; font-family: var(--mono); font-size:11px; font-weight:700; color:var(--text-2); background: var(--surface-2); border:1px solid var(--line); }
|
||||
.rc .rt { flex:1; min-width:0; }
|
||||
.rc .rt b { font-size: 14.5px; font-weight: 600; }
|
||||
.rc .rt .rs { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }
|
||||
.rc .rt .rs .mono { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); }
|
||||
.rc .rt .rs .prov { color: var(--intel); }
|
||||
.rc .meta { font-family: var(--mono); font-size: 11px; color: var(--text-dim); white-space:nowrap; }
|
||||
.bdg { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; display:inline-flex; align-items:center; gap:5px; white-space:nowrap; }
|
||||
.bdg.ok { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.bdg.warn { color: var(--attention); background: var(--honey-wash); }
|
||||
.bdg.risk { color: var(--risk); background: var(--risk-wash); }
|
||||
.bdg.off { color: var(--text-dim); background: var(--surface-2); }
|
||||
.lnk { font-size: 12px; font-weight: 600; color: var(--text-2); cursor:pointer; } .lnk:hover { color: var(--honey); }
|
||||
.rbtn { font-size: 12px; font-weight: 650; padding: 7px 13px; border-radius: 8px; cursor:pointer; border:1px solid transparent; }
|
||||
.rbtn.go { background: var(--honey); color:#1a1407; } .rbtn.go:hover { background: var(--honey-bright); }
|
||||
.rbtn.ghost { background: var(--surface-2); color: var(--text-2); border-color: var(--line-strong); } .rbtn.ghost:hover { border-color: var(--honey-line); color: var(--text); }
|
||||
.rbtn.danger { background: transparent; color: var(--risk); border-color: color-mix(in srgb,var(--risk) 35%,transparent); }
|
||||
.acts { display:flex; gap:8px; align-items:center; }
|
||||
|
||||
/* toggle */
|
||||
.sw { width: 38px; height: 22px; border-radius: 999px; background: var(--surface-3); border:1px solid var(--line-strong); position:relative; cursor:pointer; transition:.16s; flex:none; }
|
||||
.sw::after { content:''; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:999px; background: var(--text-muted); transition:.16s; }
|
||||
.sw.on { background: var(--honey); border-color: var(--honey); } .sw.on::after { left:18px; background:#1a1407; }
|
||||
|
||||
/* approval cards */
|
||||
.appr { border:1px solid var(--line-soft); border-radius: var(--r-lg); background: var(--surface); padding: 18px; }
|
||||
.appr.hot { border-color: color-mix(in srgb,var(--attention) 35%,transparent); background: var(--honey-wash); }
|
||||
.appr .at { display:flex; align-items:center; gap:10px; margin-bottom: 8px; }
|
||||
.appr .at b { font-size: 14.5px; font-weight: 650; }
|
||||
.appr p { margin: 0 0 14px; font-size: 13px; color: var(--text-muted); line-height:1.55; }
|
||||
.appr p .mono { font-family: var(--mono); font-size:11.5px; color: var(--text-2); }
|
||||
.appr .ar { display:flex; gap:9px; align-items:center; }
|
||||
|
||||
/* usage */
|
||||
.ustat { display:grid; grid-template-columns: repeat(3,1fr); gap:14px; margin-bottom: 22px; }
|
||||
.ust { padding: 18px; border-radius: var(--r-lg); border:1px solid var(--line-soft); background: var(--surface); }
|
||||
.ust .v { font-size: 30px; font-weight: 750; letter-spacing:-0.03em; line-height:1; }
|
||||
.ust .l { font-size: 12px; color: var(--text-muted); margin-top: 7px; }
|
||||
.ubar { display:grid; grid-template-columns: 130px 1fr 70px; gap:14px; align-items:center; margin-bottom: 10px; }
|
||||
.ubar .ul { font-size: 13px; font-weight:600; text-align:right; }
|
||||
.ubar .ut { height: 26px; border-radius: 7px; background: var(--surface-2); border:1px solid var(--line-soft); overflow:hidden; }
|
||||
.ubar .uf { height:100%; }
|
||||
.ubar .uv { font-family: var(--mono); font-size: 12.5px; color: var(--text-2); }
|
||||
|
||||
@media (max-width: 800px){ .rail { width: 64px; } .rail .rh, .ritem span.txt, .ritem .ct { display:none; } .ustat { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Power surfaces · ⌘K destinations</span>
|
||||
<span class="vlabel" id="vlabel"><b>One template</b>, every tool — clean & consistent</span>
|
||||
<div class="right"><span class="hint">these all live behind ⌘K</span><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="app">
|
||||
<nav class="rail" id="rail">
|
||||
<div class="rh">Behind ⌘K</div>
|
||||
<div class="ritem on" data-s="tools"><svg viewBox="0 0 24 24"><path d="M7 8a4 4 0 0 0 0 8h2M17 8a4 4 0 0 1 0 8h-2M8 12h8"/></svg><span class="txt">Tools</span><span class="ct">7</span></div>
|
||||
<div class="ritem" data-s="auto"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/></svg><span class="txt">Automations</span><span class="ct warn">1</span></div>
|
||||
<div class="ritem" data-s="appr"><svg viewBox="0 0 24 24"><path d="M9 12l2 2 4-4M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/></svg><span class="txt">Approvals</span><span class="ct warn">2</span></div>
|
||||
<div class="ritem" data-s="vault"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="12" cy="12" r="3"/></svg><span class="txt">Vault</span><span class="ct">5</span></div>
|
||||
<div class="ritem" data-s="usage"><svg viewBox="0 0 24 24"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></svg><span class="txt">Usage</span></div>
|
||||
</nav>
|
||||
|
||||
<div class="main">
|
||||
<div class="shead">
|
||||
<div><h1 id="sTitle">Tools & connections</h1><p id="sSub">Everything your agents can reach — integrations, MCP servers, and skills.</p></div>
|
||||
<button class="pa" id="sAction"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg><span id="sActionT">Add a tool</span></button>
|
||||
</div>
|
||||
<div class="body" id="body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const head = {
|
||||
tools: ['Tools & connections','Everything your agents can reach — integrations, MCP servers, and skills.','Add a tool'],
|
||||
auto: ['Automations','Work that runs on a schedule, while you\u2019re away.','New automation'],
|
||||
appr: ['Approvals','Actions your agents are holding until you say go.','Approval settings'],
|
||||
vault: ['Vault','Secrets, encrypted on this machine. Agents use them; they never see them.','Add secret'],
|
||||
usage: ['Usage & cost','Tokens and spend across models and workspaces.','Set budget'],
|
||||
};
|
||||
|
||||
function rc(icon, title, sub, right){ return `<div class="rc"><div class="ri">${icon}</div><div class="rt"><b>${title}</b><div class="rs">${sub}</div></div>${right}</div>`; }
|
||||
function tog(on){ return `<div class="sw ${on?'on':''}" onclick="this.classList.toggle('on')"></div>`; }
|
||||
|
||||
const panels = {
|
||||
tools: () => `
|
||||
<div class="grp">Connected integrations</div>
|
||||
<div class="rows">
|
||||
${rc('SF','Salesforce','<span class="rs">CRM · used by 2 agents · <span class="mono">Q2 Pricing</span></span>','<div class="acts"><span class="bdg ok">● Connected</span><span class="lnk">Manage</span></div>')}
|
||||
${rc('Sl','Slack','Notifications & digests','<div class="acts"><span class="bdg ok">● Connected</span><span class="lnk">Manage</span></div>')}
|
||||
${rc('Gh','GitHub','Repos & issues','<div class="acts"><span class="bdg ok">● Connected</span><span class="lnk">Manage</span></div>')}
|
||||
</div>
|
||||
<div class="grp">MCP servers · 21 tools</div>
|
||||
<div class="rows">
|
||||
${rc('fs','Filesystem','<span class="rs">read/write workspace files · <span class="mono">6 tools</span></span>','<span class="bdg ok">● Active</span>')}
|
||||
${rc('web','Web search','<span class="rs">live retrieval · <span class="mono">3 tools</span></span>','<span class="bdg ok">● Active</span>')}
|
||||
</div>
|
||||
<div class="grp">Available</div>
|
||||
<div class="rows">
|
||||
${rc('No','Notion','Docs & wikis','<button class="rbtn ghost">Connect</button>')}
|
||||
${rc('Li','Linear','Issues & projects','<button class="rbtn ghost">Connect</button>')}
|
||||
</div>`,
|
||||
auto: () => `
|
||||
<div class="rows">
|
||||
${rc('<svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--healthy)" stroke-width=1.8><circle cx=12 cy=12 r=8/><path d="M12 8v4l3 2"/></svg>','Weekly digest','<span class="rs"><span class="mono">Mon 09:00</span> · last ran 3d ago · ok</span>','<div class="acts"><span class="lnk">Logs</span>'+tog(true)+'</div>')}
|
||||
${rc('<svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--risk)" stroke-width=1.8><path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>','Q2 pipeline sync → Salesforce','<span class="rs"><span class="mono">Daily 02:00</span> · failed 02:14 · auth expired</span>','<div class="acts"><span class="bdg risk">Failed</span><button class="rbtn go">Fix & retry</button>'+tog(true)+'</div>')}
|
||||
${rc('<svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--intel)" stroke-width=1.8><path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/></svg>','Nightly memory consolidation','<span class="rs"><span class="mono">Nightly 03:00</span> · last ran ok · +14 memories</span>','<div class="acts"><span class="lnk">Logs</span>'+tog(true)+'</div>')}
|
||||
${rc('<svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--text-dim)" stroke-width=1.8><circle cx=12 cy=12 r=8/><path d="M12 8v4l3 2"/></svg>','Competitor price watch','<span class="rs"><span class="mono">Weekly</span> · paused</span>','<div class="acts"><span class="bdg off">Paused</span>'+tog(false)+'</div>')}
|
||||
</div>`,
|
||||
appr: () => `
|
||||
<div class="grp">Waiting on you</div>
|
||||
<div class="rows" style="gap:12px">
|
||||
<div class="appr hot"><div class="at"><span class="bdg warn">Medium risk</span><b>Export pricing table to Salesforce</b></div><p>Research-synth wants to write to an external system — <span class="mono">Salesforce › Q2 Pricing</span>. 9 rows, no deletes. From the Competitive Intelligence chat.</p><div class="ar"><button class="rbtn go">Approve</button><button class="rbtn ghost">Deny</button><span class="lnk">Always allow for this workspace</span></div></div>
|
||||
<div class="appr"><div class="at"><span class="bdg off">Low risk</span><b>Send the board update email</b></div><p>Deck-builder drafted an email to <span class="mono">board@egzakta</span>. Reads from this workspace only.</p><div class="ar"><button class="rbtn go">Approve</button><button class="rbtn ghost">Deny</button><span class="lnk">Review draft</span></div></div>
|
||||
</div>
|
||||
<div class="grp">Recently decided</div>
|
||||
<div class="rows">
|
||||
${rc('✓','Read competitor sites','<span class="rs">approved 2h ago · web fetch</span>','<span class="bdg ok">Approved</span>')}
|
||||
</div>`,
|
||||
vault: () => `
|
||||
<div class="rows">
|
||||
${rc('🔑','ANTHROPIC_API_KEY','<span class="rs"><span class="mono">sk-ant-•••••••••••3a9f</span> · used by the agent runtime</span>','<div class="acts"><span class="lnk">Rotate</span><span class="lnk">Reveal</span></div>')}
|
||||
${rc('🔑','OPENAI_API_KEY','<span class="rs"><span class="mono">sk-•••••••••••7c20</span> · LiteLLM routing</span>','<div class="acts"><span class="lnk">Rotate</span><span class="lnk">Reveal</span></div>')}
|
||||
${rc('🔑','Salesforce token','<span class="rs"><span class="mono">••••••••</span> · 1 connector · <span style="color:var(--risk)">expired</span></span>','<div class="acts"><button class="rbtn go">Renew</button></div>')}
|
||||
${rc('🔑','GitHub PAT','<span class="rs"><span class="mono">ghp_•••••••••••</span> · 1 connector</span>','<div class="acts"><span class="lnk">Rotate</span></div>')}
|
||||
</div>
|
||||
<div class="grp">How it\u2019s stored</div>
|
||||
<div class="rc"><div class="ri"><svg width=16 height=16 viewBox="0 0 24 24" fill=none stroke="var(--healthy)" stroke-width=1.8><path d="M12 3l8 4v5c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V7z"/><path d="M9 12l2 2 4-4"/></svg></div><div class="rt"><b>Encrypted, on this machine</b><div class="rs">Secrets live in the local vault. Agents reference them by name to call tools — the key value is never placed into a prompt or shown to a model.</div></div></div>`,
|
||||
usage: () => `
|
||||
<div class="ustat">
|
||||
<div class="ust"><div class="v">$12.40</div><div class="l">This month · est.</div></div>
|
||||
<div class="ust"><div class="v" style="color:var(--intel)">4.2M</div><div class="l">Tokens</div></div>
|
||||
<div class="ust"><div class="v" style="color:var(--healthy)">$50</div><div class="l">Budget · 25% used</div></div>
|
||||
</div>
|
||||
<div class="grp">By model</div>
|
||||
<div>
|
||||
<div class="ubar"><span class="ul">Claude Sonnet</span><div class="ut"><div class="uf" style="width:62%;background:linear-gradient(90deg,var(--honey-deep),var(--honey))"></div></div><span class="uv">$7.70</span></div>
|
||||
<div class="ubar"><span class="ul">GPT-5</span><div class="ut"><div class="uf" style="width:24%;background:var(--work)"></div></div><span class="uv">$3.00</span></div>
|
||||
<div class="ubar"><span class="ul">Qwen · local</span><div class="ut"><div class="uf" style="width:6%;background:var(--healthy)"></div></div><span class="uv">$0.00</span></div>
|
||||
</div>
|
||||
<div class="grp">By workspace</div>
|
||||
<div class="rows">
|
||||
${rc('C','Competitive Intelligence','<span class="rs">2.4M tokens</span>','<span class="meta">$6.90</span>')}
|
||||
${rc('B','Q2 Board Deck','<span class="rs">1.1M tokens</span>','<span class="meta">$3.80</span>')}
|
||||
${rc('R','Customer Research','<span class="rs">0.7M tokens</span>','<span class="meta">$1.70</span>')}
|
||||
</div>`,
|
||||
};
|
||||
|
||||
function show(s){
|
||||
document.querySelectorAll('.ritem').forEach(r => r.classList.toggle('on', r.dataset.s===s));
|
||||
document.getElementById('sTitle').innerHTML = head[s][0];
|
||||
document.getElementById('sSub').innerHTML = head[s][1];
|
||||
document.getElementById('sActionT').textContent = head[s][2];
|
||||
document.getElementById('body').innerHTML = panels[s]();
|
||||
document.getElementById('body').scrollTop = 0;
|
||||
}
|
||||
document.getElementById('rail').addEventListener('click', e => { const r = e.target.closest('.ritem'); if(r) show(r.dataset.s); });
|
||||
show('tools');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,338 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Workspace</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); }
|
||||
.controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
|
||||
/* ── workspace header ── */
|
||||
.wshead { padding: 30px 36px 0; max-width: 1080px; margin: 0 auto; }
|
||||
.crumbs { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
|
||||
.crumbs b { color: var(--text-2); font-weight: 500; }
|
||||
.wtitle-row { display: flex; align-items: center; gap: 16px; }
|
||||
.wtitle-row .wmark { width: 46px; height: 52px; flex: none; display: grid; place-items: center; font-weight: 800; font-size: 20px; color: #1a1407; background: linear-gradient(150deg, var(--honey-bright), var(--honey-deep)); box-shadow: var(--honey-glow); }
|
||||
.wtitle-row h1 { font-size: 28px; font-weight: 650; letter-spacing: -0.02em; margin: 0; }
|
||||
.wtitle-row .wmeta { font-size: 13px; color: var(--text-muted); margin-top: 3px; display: flex; gap: 14px; flex-wrap: wrap; }
|
||||
.wtitle-row .wmeta span { display: inline-flex; align-items: center; gap: 6px; }
|
||||
.wtitle-row .actions { margin-left: auto; display: flex; gap: 9px; }
|
||||
.btn { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-family: var(--sans); font-size: 13.5px; font-weight: 650; padding: 10px 17px; border-radius: 10px; border: 1px solid transparent; text-decoration:none; transition:.15s; }
|
||||
.btn-primary { background: var(--honey); color: #1a1407; }
|
||||
.btn-primary:hover { background: var(--honey-bright); }
|
||||
.btn-ghost { background: var(--surface); color: var(--text-2); border-color: var(--line-strong); }
|
||||
.btn-ghost:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
|
||||
/* ── tabs ── */
|
||||
.tabs { display: flex; gap: 2px; margin: 24px 0 0; border-bottom: 1px solid var(--line-soft); }
|
||||
.tab { font-size: 14px; font-weight: 600; color: var(--text-muted); padding: 12px 16px; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; transition:.14s; display:flex; align-items:center; gap:8px; }
|
||||
.tab:hover { color: var(--text); }
|
||||
.tab.on { color: var(--text); border-bottom-color: var(--honey); }
|
||||
.tab .cnt { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
|
||||
/* ── content ── */
|
||||
.content { max-width: 1080px; margin: 0 auto; padding: 28px 36px 60px; }
|
||||
.grid { display: grid; grid-template-columns: 1.7fr 1fr; gap: 22px; }
|
||||
.col { display: flex; flex-direction: column; gap: 22px; min-width: 0; }
|
||||
.sec-h { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); margin: 0 0 14px; display: flex; align-items: center; gap: 10px; }
|
||||
.sec-h .ic { width: 15px; height: 15px; }
|
||||
.sec-h .ic svg { width: 15px; height: 15px; stroke: var(--honey); fill: none; stroke-width: 1.8; }
|
||||
|
||||
.card { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); padding: 22px; }
|
||||
.summary { font-size: 15.5px; line-height: 1.6; color: var(--text-2); }
|
||||
.summary b { color: var(--text); font-weight: 600; }
|
||||
|
||||
/* knows / memory cards */
|
||||
.knows { display: grid; gap: 10px; }
|
||||
.fact { display: grid; grid-template-columns: 30px 1fr; gap: 13px; padding: 13px 15px; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft); transition:.15s; }
|
||||
.fact:hover { border-color: var(--honey-line); }
|
||||
.fact .fi { width: 30px; height: 34px; flex:none; display:grid; place-items:center; }
|
||||
.fact .fi svg { width: 15px; height: 15px; stroke: #1a1407; fill:none; stroke-width:2; }
|
||||
.fact .ft { font-size: 14px; line-height: 1.5; color: var(--text); }
|
||||
.fact .ft b { font-weight: 650; }
|
||||
.fact .prov { margin-top: 7px; display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); }
|
||||
.fact .prov .src { color: var(--intel); }
|
||||
|
||||
/* artifacts */
|
||||
.arts { display: grid; gap: 9px; }
|
||||
.art { display: flex; align-items: center; gap: 13px; padding: 12px 15px; border-radius: var(--r); border: 1px solid var(--line-soft); background: var(--surface); cursor: pointer; transition:.15s; }
|
||||
.art:hover { border-color: var(--honey-line); background: var(--surface-2); }
|
||||
.art .ai { width: 32px; height: 32px; border-radius: 8px; flex:none; display:grid; place-items:center; font-family: var(--mono); font-size: 10px; font-weight: 700; }
|
||||
.art .at { flex: 1; min-width: 0; }
|
||||
.art .at b { font-size: 14px; font-weight: 600; display: block; }
|
||||
.art .at span { font-size: 12px; color: var(--text-dim); }
|
||||
.art .when { font-size: 11.5px; color: var(--text-dim); font-family: var(--mono); }
|
||||
|
||||
/* right rail */
|
||||
.stat-line { display: flex; align-items: center; gap: 10px; padding: 11px 0; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; }
|
||||
.stat-line:last-child { border-bottom: 0; }
|
||||
.stat-line .l { color: var(--text-muted); flex: 1; }
|
||||
.stat-line .v { font-weight: 600; }
|
||||
.person { display: flex; align-items: center; gap: 11px; padding: 9px 0; }
|
||||
.person .pa { width: 30px; height: 30px; border-radius: 999px; flex:none; display:grid; place-items:center; font-size: 11px; font-weight: 700; color: #1a1407; }
|
||||
.person .pn { flex:1; font-size: 13.5px; }
|
||||
.person .pr { font-size: 11.5px; color: var(--text-dim); }
|
||||
.agentrow { display:flex; align-items:center; gap:10px; padding: 10px 0; border-bottom: 1px solid var(--line-soft); font-size:13.5px; }
|
||||
.agentrow:last-child { border-bottom:0; }
|
||||
.agentrow .an { flex:1; }
|
||||
.agentrow .am { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
||||
|
||||
/* ── memory-forward (variation B) ── */
|
||||
.graph-wrap { position: relative; height: 360px; border-radius: var(--r-xl); border: 1px solid var(--line); background: radial-gradient(80% 80% at 50% 45%, var(--surface), var(--bg-2)); overflow: hidden; }
|
||||
.graph-wrap .comb { position: absolute; inset: 0; opacity: .5; }
|
||||
.node { position: absolute; transform: translate(-50%,-50%); display: grid; place-items: center; text-align: center; }
|
||||
.node .nb { padding: 9px 13px; border-radius: 11px; background: var(--surface); border: 1px solid var(--line-strong); font-size: 12.5px; font-weight: 600; box-shadow: var(--shadow); white-space: nowrap; }
|
||||
.node.center .nb { background: linear-gradient(150deg, var(--surface-2), var(--surface)); border-color: var(--honey-line); box-shadow: var(--honey-glow); padding: 13px 18px; }
|
||||
.node.center .nb b { font-size: 14px; }
|
||||
.node .tag { font-family: var(--mono); font-size: 9px; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 5px; }
|
||||
.node.person .tag { color: var(--work); } .node.person .nb { border-color: color-mix(in srgb, var(--work) 40%, var(--line-strong)); }
|
||||
.node.concept .tag { color: var(--intel); } .node.concept .nb { border-color: color-mix(in srgb, var(--intel) 40%, var(--line-strong)); }
|
||||
.node.org .tag { color: var(--risk); } .node.org .nb { border-color: color-mix(in srgb, var(--risk) 40%, var(--line-strong)); }
|
||||
.node.proj .tag { color: var(--healthy); } .node.proj .nb { border-color: color-mix(in srgb, var(--healthy) 40%, var(--line-strong)); }
|
||||
.graph-wrap svg { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.gline { stroke: var(--line-strong); stroke-width: 1.2; }
|
||||
.glegend { position: absolute; bottom: 14px; left: 16px; display: flex; gap: 14px; font-family: var(--mono); font-size: 10px; color: var(--text-dim); }
|
||||
.glegend span { display:inline-flex; align-items:center; gap:6px; }
|
||||
|
||||
.timeline { display: grid; gap: 0; }
|
||||
.tl { display: grid; grid-template-columns: 64px 1fr; gap: 16px; padding: 14px 0; border-top: 1px solid var(--line-soft); }
|
||||
.tl:first-child { border-top: 0; }
|
||||
.tl .when { font-family: var(--mono); font-size: 11px; color: var(--text-dim); padding-top: 2px; }
|
||||
.tl .ev b { font-weight: 600; }
|
||||
.tl .ev { font-size: 14px; color: var(--text-2); line-height: 1.5; }
|
||||
.tl .ev .src { font-family: var(--mono); font-size: 10.5px; color: var(--intel); margin-left: 6px; }
|
||||
|
||||
.hidden { display: none !important; }
|
||||
.emptytab { padding: 60px 20px; text-align: center; color: var(--text-muted); }
|
||||
.emptytab .mono { font-family: var(--mono); font-size: 12px; color: var(--text-dim); letter-spacing: .08em; }
|
||||
@media (max-width: 820px){ .grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Workspace · variation</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="a">A · Overview + tabs</button>
|
||||
<button data-v="b">B · Memory-forward</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel"><b>Overview + tabs</b> — calm home for a project</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="wshead">
|
||||
<div class="crumbs">Home <span>›</span> <b>Competitive Intelligence</b></div>
|
||||
<div class="wtitle-row">
|
||||
<div class="wmark hex">C</div>
|
||||
<div>
|
||||
<h1>Competitive Intelligence</h1>
|
||||
<div class="wmeta">
|
||||
<span><span class="dot dot-live" style="background:var(--healthy)"></span>1 agent live</span>
|
||||
<span>142 memories</span>
|
||||
<span>9 sources</span>
|
||||
<span>updated 2h ago</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn btn-ghost">Memory</button>
|
||||
<button class="btn btn-primary">Continue →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs" id="tabs">
|
||||
<div class="tab on" data-t="overview">Overview</div>
|
||||
<div class="tab" data-t="chat">Chat <span class="cnt">3</span></div>
|
||||
<div class="tab" data-t="memory">Memory <span class="cnt">142</span></div>
|
||||
<div class="tab" data-t="artifacts">Artifacts <span class="cnt">7</span></div>
|
||||
<div class="tab" data-t="files">Files <span class="cnt">12</span></div>
|
||||
<div class="tab" data-t="team">Team <span class="cnt">4</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════ VARIATION A — OVERVIEW + TABS ══════ -->
|
||||
<div class="content view" id="view-a">
|
||||
<div id="tab-overview">
|
||||
<div class="grid">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="summary">This workspace tracks the <b>persistent-memory competitor landscape</b> for the Q2 board cycle. Waggle has mapped <b>9 rivals</b>, pulled current pricing, and drafted a teardown — the live thread is mid-flight on turning the opening into a board brief.</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="sec-h"><span class="ic"><svg viewBox="0 0 24 24"><path d="M12 5a3 3 0 0 0-3 3 3 3 0 0 0-3 3 3 3 0 0 0 1 5 3 3 0 0 0 5 1 3 3 0 0 0 5-1 3 3 0 0 0 1-5 3 3 0 0 0-3-3 3 3 0 0 0-3-3Z"/></svg></span>What Waggle knows</div>
|
||||
<div class="knows" id="knowsA"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="sec-h"><span class="ic"><svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6"/></svg></span>Recent work</div>
|
||||
<div class="arts" id="artsA"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="sec-h" style="margin-bottom:6px">Status</div>
|
||||
<div class="stat-line"><span class="l">Agent</span><span class="v" style="color:var(--healthy)"><span class="dot dot-live" style="background:var(--healthy)"></span> Research-synth · live</span></div>
|
||||
<div class="stat-line"><span class="l">Model</span><span class="v">auto · Claude Sonnet</span></div>
|
||||
<div class="stat-line"><span class="l">Memories</span><span class="v">142 <span style="color:var(--healthy)">+6 today</span></span></div>
|
||||
<div class="stat-line"><span class="l">Needs review</span><span class="v" style="color:var(--attention)">3 memories</span></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="sec-h" style="margin-bottom:6px">Up next</div>
|
||||
<div class="agentrow"><span class="dot" style="background:var(--work)"></span><span class="an">Board brief from teardown</span><span class="am">draft</span></div>
|
||||
<div class="agentrow"><span class="dot" style="background:var(--attention)"></span><span class="an">Export table → Salesforce</span><span class="am">awaiting you</span></div>
|
||||
<div class="agentrow"><span class="dot" style="background:var(--healthy)"></span><span class="an">Weekly digest</span><span class="am">17:00</span></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="sec-h" style="margin-bottom:6px">Team</div>
|
||||
<div id="teamA"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-other" class="hidden">
|
||||
<div class="emptytab">
|
||||
<p style="font-size:16px;color:var(--text-2);margin-bottom:6px" id="otherTitle">Chat</p>
|
||||
<p class="mono">This tab is wired in the full prototype — Overview is the focus of this concept pass.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ══════ VARIATION B — MEMORY-FORWARD ══════ -->
|
||||
<div class="content view hidden" id="view-b">
|
||||
<div class="sec-h" style="margin-bottom:14px"><span class="ic"><svg viewBox="0 0 24 24"><circle cx="5" cy="6" r="2"/><circle cx="19" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M7 6h10M6 8l5 8M18 8l-5 8"/></svg></span>What this workspace knows · knowledge graph</div>
|
||||
<div class="graph-wrap">
|
||||
<div class="comb"></div>
|
||||
<svg viewBox="0 0 900 360" preserveAspectRatio="none" aria-hidden="true">
|
||||
<line class="gline" x1="450" y1="180" x2="180" y2="80"></line>
|
||||
<line class="gline" x1="450" y1="180" x2="720" y2="80"></line>
|
||||
<line class="gline" x1="450" y1="180" x2="150" y2="265"></line>
|
||||
<line class="gline" x1="450" y1="180" x2="740" y2="270"></line>
|
||||
<line class="gline" x1="450" y1="180" x2="450" y2="305"></line>
|
||||
<line class="gline" x1="180" y1="80" x2="450" y2="305"></line>
|
||||
</svg>
|
||||
<div class="node center" style="left:50%;top:50%"><div class="nb"><b>Competitive Intelligence</b></div></div>
|
||||
<div class="node org" style="left:20%;top:22%"><div class="tag">Competitor</div><div class="nb">Mem0 · cloud-only</div></div>
|
||||
<div class="node org" style="left:80%;top:22%"><div class="tag">Competitor</div><div class="nb">Letta · agent-centric</div></div>
|
||||
<div class="node concept" style="left:17%;top:74%"><div class="tag">Concept</div><div class="nb">Local-first moat</div></div>
|
||||
<div class="node concept" style="left:82%;top:75%"><div class="tag">Decision</div><div class="nb">Target regulated</div></div>
|
||||
<div class="node person" style="left:50%;top:85%"><div class="tag">Person</div><div class="nb">Mara · owner</div></div>
|
||||
</div>
|
||||
<div class="glegend">
|
||||
<span><span class="dot" style="background:var(--work)"></span>People</span>
|
||||
<span><span class="dot" style="background:var(--intel)"></span>Concepts</span>
|
||||
<span><span class="dot" style="background:var(--risk)"></span>Orgs</span>
|
||||
<span><span class="dot" style="background:var(--healthy)"></span>Decisions</span>
|
||||
</div>
|
||||
|
||||
<div class="grid" style="margin-top:28px">
|
||||
<div class="col">
|
||||
<div class="sec-h">Memory timeline</div>
|
||||
<div class="timeline" id="timelineB"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="sec-h" style="margin-bottom:6px">Provenance</div>
|
||||
<div class="stat-line"><span class="l">From your chats</span><span class="v">88</span></div>
|
||||
<div class="stat-line"><span class="l">From web sources</span><span class="v">41</span></div>
|
||||
<div class="stat-line"><span class="l">Imported</span><span class="v">13</span></div>
|
||||
<div class="stat-line"><span class="l">Awaiting review</span><span class="v" style="color:var(--attention)">3</span></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="sec-h" style="margin-bottom:10px">Every memory carries a source</div>
|
||||
<p style="margin:0;font-size:13.5px;color:var(--text-muted);line-height:1.6">Click any node or fact and Waggle shows exactly where it came from, when, and which model wrote it — nothing in the hive is unattributed.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const HONEY='linear-gradient(150deg,var(--honey-bright),var(--honey-deep))';
|
||||
const CHECK='<svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';
|
||||
|
||||
const facts = [
|
||||
{ t:'<b>Mem0</b> is cloud-only and raised prices ~15% since March.', src:'web · mem0.ai', when:'2h ago' },
|
||||
{ t:'Only <b>2 of 9</b> rivals ship local-first memory.', src:'teardown.md', when:'2h ago' },
|
||||
{ t:'Mara wants the board brief to <b>lead with the regulated-industries opening</b>.', src:'chat · Tue', when:'2d ago' },
|
||||
{ t:'Pricing model assumes a <b>new tier lifts ARPU ~12%</b>.', src:'Pricing Model', when:'3d ago' },
|
||||
];
|
||||
document.getElementById('knowsA').innerHTML = facts.map(f=>`
|
||||
<div class="fact"><div class="fi hex" style="background:${HONEY}">${CHECK}</div><div><div class="ft">${f.t}</div><div class="prov">⬡ <span class="src">${f.src}</span> · ${f.when}</div></div></div>`).join('');
|
||||
|
||||
const arts = [
|
||||
{ ext:'MD', c:'var(--work)', n:'teardown.md', s:'Q2 competitive teardown · 9 competitors', when:'2h ago' },
|
||||
{ ext:'XLS', c:'var(--healthy)', n:'pricing-landscape.xlsx', s:'Competitor pricing table', when:'2h ago' },
|
||||
{ ext:'PDF', c:'var(--risk)', n:'mem0-teardown.pdf', s:'Deep-dive on the category leader', when:'1d ago' },
|
||||
];
|
||||
document.getElementById('artsA').innerHTML = arts.map(a=>`
|
||||
<div class="art"><div class="ai" style="background:color-mix(in srgb, ${a.c} 18%, transparent);color:${a.c}">${a.ext}</div><div class="at"><b>${a.n}</b><span>${a.s}</span></div><span class="when">${a.when}</span></div>`).join('');
|
||||
|
||||
const team = [
|
||||
{ i:'M', c:'var(--honey)', n:'Mara K.', r:'Owner' },
|
||||
{ i:'R', c:'var(--work)', n:'Research-synth', r:'Agent · live' },
|
||||
{ i:'D', c:'var(--intel)', n:'Deck-builder', r:'Agent · idle' },
|
||||
{ i:'J', c:'var(--healthy)', n:'Jonas P.', r:'Editor' },
|
||||
];
|
||||
document.getElementById('teamA').innerHTML = team.map(p=>`
|
||||
<div class="person"><div class="pa" style="background:${p.c}">${p.i}</div><div class="pn">${p.n}</div><div class="pr">${p.r}</div></div>`).join('');
|
||||
|
||||
const timeline = [
|
||||
{ when:'2h ago', ev:'Folded <b>6 memories</b> from the teardown run', src:'mem://hive' },
|
||||
{ when:'2h ago', ev:'Learned <b>Mem0 pricing changed</b> — flagged vs your model', src:'web' },
|
||||
{ when:'2d ago', ev:'Captured Mara\u2019s steer: <b>lead with regulated</b>', src:'chat' },
|
||||
{ when:'1w ago', ev:'Imported <b>March landscape</b> notes', src:'import' },
|
||||
];
|
||||
document.getElementById('timelineB').innerHTML = timeline.map(t=>`
|
||||
<div class="tl"><div class="when">${t.when}</div><div class="ev">${t.ev}<span class="src">⬡ ${t.src}</span></div></div>`).join('');
|
||||
|
||||
/* tabs (variation A) */
|
||||
const tabs = document.getElementById('tabs');
|
||||
tabs.addEventListener('click', e => {
|
||||
const t = e.target.closest('.tab'); if(!t) return;
|
||||
[...tabs.children].forEach(x=>x.classList.toggle('on', x===t));
|
||||
const isOverview = t.dataset.t==='overview';
|
||||
document.getElementById('tab-overview').classList.toggle('hidden', !isOverview);
|
||||
document.getElementById('tab-other').classList.toggle('hidden', isOverview);
|
||||
if(!isOverview) document.getElementById('otherTitle').textContent = t.textContent.trim().replace(/\s*\d+$/,'');
|
||||
});
|
||||
|
||||
/* variation switch */
|
||||
const labels = { a:'<b>Overview + tabs</b> — calm home for a project', b:'<b>Memory-forward</b> — the graph leads' };
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => {
|
||||
const b = e.target.closest('button'); if(!b) return;
|
||||
[...seg.children].forEach(x=>x.classList.toggle('on', x===b));
|
||||
document.getElementById('view-a').classList.toggle('hidden', b.dataset.v!=='a');
|
||||
document.getElementById('view-b').classList.toggle('hidden', b.dataset.v!=='b');
|
||||
document.getElementById('vlabel').innerHTML = labels[b.dataset.v];
|
||||
document.querySelector('.stage').scrollTop = 0;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,172 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Waggle · Workspaces</title>
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
<link rel="stylesheet" href="../styles/waggle.css">
|
||||
<style>
|
||||
body { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.controls { flex: none; display: flex; align-items: center; gap: 14px; padding: 11px 20px; border-bottom: 1px solid var(--line-soft); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(10px); z-index: 30; }
|
||||
.controls .lab { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
|
||||
.seg { display: inline-flex; padding: 3px; gap: 3px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--line-soft); }
|
||||
.seg button { font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--text-muted); padding: 6px 13px; border-radius: 7px; transition: .14s; white-space: nowrap; }
|
||||
.seg button.on { background: var(--honey); color: #1a1407; }
|
||||
.controls .vlabel { font-size: 12.5px; color: var(--text-muted); } .controls .vlabel b { color: var(--text); font-weight: 600; }
|
||||
.controls .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.tbtn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--surface); color: var(--text-2); cursor: pointer; }
|
||||
.tbtn:hover { border-color: var(--honey-line); color: var(--honey); }
|
||||
.stage { flex: 1; min-height: 0; overflow: auto; }
|
||||
.wrap { max-width: 1000px; margin: 0 auto; padding: 28px 32px 60px; }
|
||||
|
||||
.head { display:flex; align-items:flex-end; gap: 16px; margin-bottom: 6px; }
|
||||
.head h1 { font-size: 28px; font-weight: 650; letter-spacing:-0.02em; margin: 0; }
|
||||
.head .new { margin-left:auto; font-size: 13px; font-weight: 650; padding: 10px 16px; border-radius: 10px; background: var(--honey); color:#1a1407; cursor:pointer; border:0; display:inline-flex; align-items:center; gap:8px; }
|
||||
.head .new:hover { background: var(--honey-bright); }
|
||||
.sub { font-size: 14px; color: var(--text-muted); margin: 0 0 22px; }
|
||||
|
||||
.toolbar { display:flex; align-items:center; gap: 12px; margin-bottom: 20px; flex-wrap: wrap; }
|
||||
.search { flex:1; min-width: 220px; display:flex; align-items:center; gap:10px; padding: 9px 14px; border-radius: 11px; border:1px solid var(--line); background: var(--surface); }
|
||||
.search:focus-within { border-color: var(--honey-line); }
|
||||
.search svg { width:16px; height:16px; stroke: var(--text-dim); fill:none; stroke-width:1.9; }
|
||||
.search input { flex:1; border:0; background:transparent; color:var(--text); font-family:var(--sans); font-size:14px; outline:none; }
|
||||
.filters { display:flex; gap:6px; }
|
||||
.filt { font-size: 12.5px; font-weight:600; color: var(--text-muted); padding: 8px 13px; border-radius: 9px; border:1px solid var(--line-soft); background: var(--surface); cursor:pointer; transition:.14s; display:inline-flex; align-items:center; gap:7px; }
|
||||
.filt:hover { color: var(--text); } .filt.on { color: var(--text); border-color: var(--honey-line); background: var(--honey-wash); }
|
||||
.filt .dot { width:7px; height:7px; }
|
||||
|
||||
/* grid */
|
||||
.grid { display:grid; grid-template-columns: repeat(2,1fr); gap: 14px; }
|
||||
.ws { padding: 18px; border-radius: var(--r-lg); border:1px solid var(--line-soft); background: var(--surface); cursor:pointer; transition:.16s; position:relative; }
|
||||
.ws:hover { border-color: var(--honey-line); transform: translateY(-2px); box-shadow: var(--shadow); }
|
||||
.ws .top { display:flex; align-items:center; gap:12px; margin-bottom: 12px; }
|
||||
.ws .wm { width:36px; height:40px; flex:none; display:grid; place-items:center; font-weight:800; font-size:14px; color:#1a1407; background: linear-gradient(150deg,var(--honey-bright),var(--honey-deep)); }
|
||||
.ws h3 { flex:1; font-size: 16px; font-weight: 650; letter-spacing:-0.01em; margin:0; }
|
||||
.ws .stbadge { font-size: 10.5px; font-weight:600; padding: 3px 9px; border-radius:999px; display:inline-flex; align-items:center; gap:5px; }
|
||||
.ws .stbadge.local { color: var(--honey); background: var(--honey-wash); }
|
||||
.ws .stbadge.virtual { color: var(--intel); background: var(--intel-wash); }
|
||||
.ws .stbadge.team { color: var(--healthy); background: var(--healthy-wash); }
|
||||
.ws p { margin: 0 0 14px; font-size: 13px; color: var(--text-muted); line-height: 1.5; min-height: 38px; }
|
||||
.ws .meta { display:flex; align-items:center; gap: 14px; font-size: 12px; color: var(--text-dim); }
|
||||
.ws .meta span { display:inline-flex; align-items:center; gap:5px; }
|
||||
.ws .meta .live { color: var(--healthy); }
|
||||
.ws .meta .pend { color: var(--attention); }
|
||||
.ws .meta .open { margin-left:auto; color: var(--honey); font-weight:650; }
|
||||
|
||||
/* table */
|
||||
.tbl { width:100%; border-collapse: collapse; }
|
||||
.tbl th { text-align:left; font-family: var(--mono); font-size: 10px; letter-spacing:.06em; text-transform:uppercase; color: var(--text-dim); font-weight:600; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); }
|
||||
.tbl td { padding: 13px 12px; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; color: var(--text-2); }
|
||||
.tbl tr { cursor:pointer; } .tbl tbody tr:hover td { background: var(--surface-2); }
|
||||
.tbl .nmc { display:flex; align-items:center; gap:11px; } .tbl .nmc .wm { width:26px; height:30px; font-size:11px; } .tbl .nmc b { color: var(--text); font-weight:600; }
|
||||
.tbl .r { text-align:right; color: var(--text-dim); font-family: var(--mono); font-size: 12px; }
|
||||
|
||||
.note { margin-top: 22px; display:flex; gap:12px; align-items:flex-start; padding: 14px 16px; border-radius: var(--r-lg); background: var(--bg-2); border:1px solid var(--line-soft); }
|
||||
.note svg { width:18px; height:18px; stroke: var(--honey); fill:none; stroke-width:1.8; flex:none; margin-top:1px; }
|
||||
.note p { margin:0; font-size: 13px; color: var(--text-muted); line-height:1.6; } .note b { color: var(--text); }
|
||||
|
||||
.hidden { display:none !important; }
|
||||
@media (max-width: 760px){ .grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="controls">
|
||||
<span class="lab">Workspaces · view</span>
|
||||
<div class="seg" id="seg">
|
||||
<button class="on" data-v="grid">Grid</button>
|
||||
<button data-v="table">Table</button>
|
||||
</div>
|
||||
<span class="vlabel" id="vlabel">Every workspace you have, in one place</span>
|
||||
<div class="right"><button class="tbtn" id="tbtn" title="Toggle theme">☾</button></div>
|
||||
</div>
|
||||
|
||||
<div class="stage">
|
||||
<div class="wrap">
|
||||
<div class="head">
|
||||
<h1>Workspaces</h1>
|
||||
<button class="new"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>New workspace</button>
|
||||
</div>
|
||||
<p class="sub">Home greets you with the day. <b style="color:var(--text-2)">This is the full shelf</b> — every workspace, where it lives, and what's happening in it.</p>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg><input id="q" placeholder="Search workspaces… or ask the agent to find one"></div>
|
||||
<div class="filters" id="filters">
|
||||
<span class="filt on" data-f="all">All <span style="color:var(--text-dim)">8</span></span>
|
||||
<span class="filt" data-f="local"><span class="dot" style="background:var(--honey)"></span>Local</span>
|
||||
<span class="filt" data-f="virtual"><span class="dot" style="background:var(--intel)"></span>Virtual</span>
|
||||
<span class="filt" data-f="team"><span class="dot" style="background:var(--healthy)"></span>Team</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="gridView" class="grid"></div>
|
||||
<div id="tableView" class="hidden"><table class="tbl"><thead><tr><th>Workspace</th><th>Storage</th><th>Memories</th><th>Agent</th><th class="r">Last active</th></tr></thead><tbody id="tbody"></tbody></table></div>
|
||||
|
||||
<div class="note">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 8h.01M11 12h1v4h1"/></svg>
|
||||
<p><b>Where this lives in the app:</b> Workspaces is one of the five places in the left rail, and it's the first thing ⌘K offers. The switcher in any workspace header opens it too — so you're never more than a click from the full shelf.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement, tbtn = document.getElementById('tbtn');
|
||||
function setTheme(t){ root.setAttribute('data-theme', t); tbtn.textContent = t==='dark'?'☾':'☀'; try{localStorage.setItem('waggle-concept-theme',t);}catch(e){} }
|
||||
setTheme((()=>{ try{ return localStorage.getItem('waggle-concept-theme')||'dark'; }catch(e){ return 'dark'; } })());
|
||||
tbtn.onclick = () => setTheme(root.getAttribute('data-theme')==='dark'?'light':'dark');
|
||||
window.addEventListener('message', e => { if(e.data && e.data.theme) setTheme(e.data.theme); });
|
||||
window.addEventListener('storage', e => { if(e.key==='waggle-concept-theme' && e.newValue) setTheme(e.newValue); });
|
||||
|
||||
const ws = [
|
||||
{ g:'C', n:'Competitive Intelligence', grp:'Research', st:'local', sum:'Q2 teardown — 9 rivals mapped, draft ready for your read.', mem:142, agent:'live', pend:3, when:'2h ago' },
|
||||
{ g:'B', n:'Q2 Board Deck', grp:'Exec', st:'local', sum:'18 slides drafted; narrative needs your voice on slide 6.', mem:88, agent:'live', pend:0, when:'yesterday' },
|
||||
{ g:'R', n:'Customer Research', grp:'Research', st:'local', sum:'31 interviews themed. Top friction: onboarding drop-off.', mem:210, agent:'idle', pend:0, when:'2d ago' },
|
||||
{ g:'P', n:'Pricing Model', grp:'Finance', st:'local', sum:'Scenario model rebuilt; new tier lifts ARPU ~12%.', mem:64, agent:'idle', pend:0, when:'3d ago' },
|
||||
{ g:'M', n:'Marketing Site Rewrite', grp:'Marketing', st:'team', sum:'Shared with 3 teammates. Hero + proof section in review.', mem:51, agent:'idle', pend:2, when:'5h ago' },
|
||||
{ g:'L', n:'Legal — Vendor Review', grp:'Legal', st:'team', sum:'Contract redlines synced across the team.', mem:38, agent:'idle', pend:0, when:'1w ago' },
|
||||
{ g:'S', n:'Scratch', grp:'Personal', st:'virtual', sum:'Quick throwaway space — notes and one-off questions.', mem:9, agent:'idle', pend:0, when:'30m ago' },
|
||||
{ g:'O', n:'Onboarding Redesign', grp:'Product', st:'local', sum:'Flow draft + 4 template options for first-run.', mem:27, agent:'idle', pend:0, when:'1h ago' },
|
||||
];
|
||||
const STL = { local:'Local · private', virtual:'Virtual · session', team:'Team · shared' };
|
||||
|
||||
let filter = 'all', query = '';
|
||||
function visible(){ return ws.filter(w => (filter==='all'||w.st===filter) && (!query || (w.n+' '+w.grp+' '+w.sum).toLowerCase().includes(query))); }
|
||||
|
||||
function renderGrid(){
|
||||
document.getElementById('gridView').innerHTML = visible().map(w => `
|
||||
<div class="ws">
|
||||
<div class="top">
|
||||
<div class="wm hex">${w.g}</div>
|
||||
<h3>${w.n}</h3>
|
||||
<span class="stbadge ${w.st}">⬡ ${STL[w.st].split(' · ')[0]}</span>
|
||||
</div>
|
||||
<p>${w.sum}</p>
|
||||
<div class="meta">
|
||||
<span>⬡ ${w.mem} memories</span>
|
||||
${w.agent==='live'?'<span class="live"><span class="dot dot-live" style="background:var(--healthy)"></span>agent live</span>':''}
|
||||
${w.pend>0?`<span class="pend">▲ ${w.pend} to review</span>`:''}
|
||||
<span class="open">Open →</span>
|
||||
</div>
|
||||
</div>`).join('') || '<p style="color:var(--text-dim);grid-column:1/-1;padding:30px;text-align:center">No workspaces match.</p>';
|
||||
}
|
||||
function renderTable(){
|
||||
document.getElementById('tbody').innerHTML = visible().map(w => `
|
||||
<tr>
|
||||
<td><div class="nmc"><div class="wm hex">${w.g}</div><div><b>${w.n}</b><div style="font-size:11.5px;color:var(--text-dim)">${w.grp}</div></div></div></td>
|
||||
<td><span class="ws"><span class="stbadge ${w.st}" style="font-size:10.5px;padding:3px 9px;border-radius:999px">⬡ ${STL[w.st]}</span></span></td>
|
||||
<td>${w.mem}</td>
|
||||
<td>${w.agent==='live'?'<span style="color:var(--healthy)">● live</span>':'<span style="color:var(--text-dim)">idle</span>'}${w.pend>0?` · <span style="color:var(--attention)">${w.pend}▲</span>`:''}</td>
|
||||
<td class="r">${w.when}</td>
|
||||
</tr>`).join('');
|
||||
}
|
||||
function render(){ renderGrid(); renderTable(); }
|
||||
render();
|
||||
|
||||
document.getElementById('q').addEventListener('input', e => { query = e.target.value.toLowerCase().trim(); render(); });
|
||||
document.getElementById('filters').addEventListener('click', e => { const f=e.target.closest('.filt'); if(!f)return; filter=f.dataset.f; document.querySelectorAll('.filt').forEach(x=>x.classList.toggle('on',x===f)); render(); });
|
||||
const seg = document.getElementById('seg');
|
||||
seg.addEventListener('click', e => { const b=e.target.closest('button'); if(!b)return; [...seg.children].forEach(x=>x.classList.toggle('on',x===b)); const grid=b.dataset.v==='grid'; document.getElementById('gridView').classList.toggle('hidden',!grid); document.getElementById('tableView').classList.toggle('hidden',grid); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
154
docs/design_handoff_waggle_app/design-files/styles/waggle.css
Normal file
@@ -0,0 +1,154 @@
|
||||
/* ═══════════════════════════════════════════════════════════════════════
|
||||
* WAGGLE — Refreshed "Hive" Design System (concept exploration)
|
||||
* A warmer, more crafted evolution of the original honey/dark theme.
|
||||
* Default = dark (warm graphite). [data-theme="light"] = warm paper.
|
||||
* ═══════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
|
||||
|
||||
:root {
|
||||
/* ── Warm dark (the hive interior) ──────────────────────────── */
|
||||
--bg: #14110b;
|
||||
--bg-2: #1a160f;
|
||||
--surface: #1f1a12;
|
||||
--surface-2: #272117;
|
||||
--surface-3: #322a1d;
|
||||
--line: #38301f;
|
||||
--line-soft: #2a2417;
|
||||
--line-strong: #4a4030;
|
||||
|
||||
--text: #f6f1e4;
|
||||
--text-2: #c8bfa9;
|
||||
--text-muted: #948a73;
|
||||
--text-dim: #6b6250;
|
||||
|
||||
/* ── Honey (the accent — used sparingly, with intent) ───────── */
|
||||
--honey: #e9a52c;
|
||||
--honey-bright: #f6c45a;
|
||||
--honey-deep: #c07e16;
|
||||
--honey-wash: rgba(233,165,44,0.10);
|
||||
--honey-line: rgba(233,165,44,0.28);
|
||||
--honey-glow: 0 0 0 1px rgba(233,165,44,0.25), 0 8px 30px -10px rgba(233,165,44,0.35);
|
||||
|
||||
/* ── Refined, desaturated semantics ─────────────────────────── */
|
||||
--work: #7aa6d6; /* dusty blue — tasks / workspaces */
|
||||
--intel: #b196dd; /* muted violet — intelligence / memory */
|
||||
--healthy: #6cb78c; /* sage — complete / healthy */
|
||||
--attention: #e9a52c; /* honey — attention / automation */
|
||||
--risk: #db8068; /* terracotta — risk / failure */
|
||||
--work-wash: rgba(122,166,214,0.12);
|
||||
--intel-wash: rgba(177,150,221,0.12);
|
||||
--healthy-wash: rgba(108,183,140,0.12);
|
||||
--risk-wash: rgba(219,128,104,0.12);
|
||||
|
||||
/* ── Depth ──────────────────────────────────────────────────── */
|
||||
--shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
|
||||
--shadow: 0 4px 24px -8px rgba(0,0,0,0.55), 0 1px 2px rgba(0,0,0,0.4);
|
||||
--shadow-lg: 0 24px 60px -20px rgba(0,0,0,0.7), 0 2px 8px rgba(0,0,0,0.4);
|
||||
--shadow-pop: 0 30px 80px -24px rgba(0,0,0,0.8);
|
||||
|
||||
/* ── Type ───────────────────────────────────────────────────── */
|
||||
--sans: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--serif: var(--sans); /* softened: display now uses the clean grotesk, not a book serif */
|
||||
--mono: 'JetBrains Mono', ui-monospace, monospace;
|
||||
|
||||
--r-sm: 8px;
|
||||
--r: 12px;
|
||||
--r-lg: 18px;
|
||||
--r-xl: 26px;
|
||||
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--bg: #f7f1e4;
|
||||
--bg-2: #f1e9d8;
|
||||
--surface: #fffdf8;
|
||||
--surface-2: #f6efe0;
|
||||
--surface-3: #efe6d2;
|
||||
--line: #e4d8be;
|
||||
--line-soft: #ede3cd;
|
||||
--line-strong: #d2c3a2;
|
||||
|
||||
--text: #211b11;
|
||||
--text-2: #5a5140;
|
||||
--text-muted: #847a64;
|
||||
--text-dim: #a99e85;
|
||||
|
||||
--honey: #b57d12;
|
||||
--honey-bright: #cf932a;
|
||||
--honey-deep: #92620a;
|
||||
--honey-wash: rgba(181,125,18,0.10);
|
||||
--honey-line: rgba(181,125,18,0.30);
|
||||
--honey-glow: 0 0 0 1px rgba(181,125,18,0.22), 0 8px 30px -12px rgba(181,125,18,0.30);
|
||||
|
||||
--work: #3f72b0;
|
||||
--intel: #7d57b8;
|
||||
--healthy: #3c8a5f;
|
||||
--attention: #b57d12;
|
||||
--risk: #c0573c;
|
||||
--work-wash: rgba(63,114,176,0.10);
|
||||
--intel-wash: rgba(125,87,184,0.10);
|
||||
--healthy-wash: rgba(60,138,95,0.10);
|
||||
--risk-wash: rgba(192,87,60,0.10);
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(60,45,20,0.06);
|
||||
--shadow: 0 6px 24px -10px rgba(60,45,20,0.18), 0 1px 2px rgba(60,45,20,0.06);
|
||||
--shadow-lg: 0 24px 60px -22px rgba(60,45,20,0.22), 0 2px 8px rgba(60,45,20,0.08);
|
||||
--shadow-pop: 0 30px 80px -26px rgba(60,45,20,0.28);
|
||||
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--sans);
|
||||
font-size: 16px;
|
||||
line-height: 1.55;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* ── Hex utility ────────────────────────────────────────────────── */
|
||||
.hex { clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); }
|
||||
|
||||
/* ── Honeycomb texture (very subtle) ────────────────────────────── */
|
||||
.comb {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='98' viewBox='0 0 56 98'%3E%3Cpath d='M28 18.5l26 15v30l-26 15-26-15v-30z M28 53.5l26 15v30l-26 15-26-15v-30z' fill='none' stroke='%23e9a52c' stroke-opacity='0.05' stroke-width='1'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* ── Focus ──────────────────────────────────────────────────────── */
|
||||
:focus-visible { outline: 2px solid var(--honey); outline-offset: 2px; }
|
||||
|
||||
::selection { background: rgba(233,165,44,0.28); color: var(--text); }
|
||||
|
||||
::-webkit-scrollbar { width: 9px; height: 9px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 6px; border: 2px solid transparent; background-clip: padding-box; }
|
||||
::-webkit-scrollbar-thumb:hover { background: var(--text-dim); background-clip: padding-box; }
|
||||
|
||||
/* ── Shared atoms used across screens ───────────────────────────── */
|
||||
.mono { font-family: var(--mono); }
|
||||
.serif { font-family: var(--serif); }
|
||||
|
||||
.pill {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
padding: 4px 10px; border-radius: 999px;
|
||||
font-size: 12px; font-weight: 500; letter-spacing: 0.01em;
|
||||
border: 1px solid var(--line); color: var(--text-2); background: var(--surface);
|
||||
}
|
||||
|
||||
.kbd {
|
||||
font-family: var(--mono); font-size: 11px;
|
||||
padding: 2px 7px; border-radius: 6px;
|
||||
border: 1px solid var(--line-strong); background: var(--surface-2); color: var(--text-2);
|
||||
box-shadow: 0 1px 0 var(--line);
|
||||
}
|
||||
|
||||
.dot { width: 7px; height: 7px; border-radius: 999px; display: inline-block; }
|
||||
@keyframes breathe { 0%,100% { opacity: 1; transform: scale(1);} 50% { opacity: .55; transform: scale(.82);} }
|
||||
.dot-live { animation: breathe 2.4s ease-in-out infinite; }
|
||||
BIN
docs/design_handoff_waggle_app/screenshots/00-landing-hero.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/01-home.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/02-chat.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/03-workspace.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/04-workspaces.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/05-ia-commandbar.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/06-launcher.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/07-storage.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/08-surfaces.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/09-marketplace.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/12-evolution.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/13-auth.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/14-billing.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/15-habit.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/16-appsurfaces.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/17-benchmark.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/18-platform.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/design_handoff_waggle_app/screenshots/19-memory-trust.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
34
docs/design_handoff_waggle_app/screenshots/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Screenshots
|
||||
|
||||
Reference captures of each design (dark theme, default/key view). These are visual
|
||||
companions to `SCREENS.md` — the spec there is authoritative for measurements, copy,
|
||||
and behavior. Every screen also supports **light mode**; toggle the ☾ button in the
|
||||
live HTML to see it.
|
||||
|
||||
| File | Screen | Spec § (SCREENS.md) |
|
||||
|------|--------|---------------------|
|
||||
| `00-landing-hero.png` | Marketing site — hero | README §9 |
|
||||
| `01-home.png` | Home / Cockpit (Editorial) | §01 |
|
||||
| `02-chat.png` | Chat runtime (split work-canvas) | §02 |
|
||||
| `03-workspace.png` | Single workspace (Overview+tabs) | §03 |
|
||||
| `04-workspaces.png` | All-workspaces index | §04 |
|
||||
| `05-ia-commandbar.png` | Sidebar + ⌘K palette (open) | §05 |
|
||||
| `06-launcher.png` | Launcher (AI-OS) | §06 |
|
||||
| `07-storage.png` | Storage & Files | §07 |
|
||||
| `08-surfaces.png` | Power surfaces (Tools) | §08 |
|
||||
| `09-marketplace.png` | Marketplace (agent suggestion) | §09 |
|
||||
| `10-onboarding-modelgate.png` | Onboarding — the model gate (step 3) | §10 |
|
||||
| `11-settings-models.png` | Settings — Models + failover pilot | §11 |
|
||||
| `12-evolution.png` | Skill evolution (version ladder) | §12 |
|
||||
| `13-auth.png` | Auth (Clerk) — sign in | §13 |
|
||||
| `14-billing.png` | Billing (Stripe) — plans | §14 |
|
||||
| `15-habit.png` | Engagement / habit loop | §15 |
|
||||
| `16-appsurfaces.png` | App surfaces (Agents) | §16 |
|
||||
| `17-benchmark.png` | Benchmarks (capability matrix) | §17 |
|
||||
| `18-platform.png` | Platform & roadmap (Tauri desktop) | §18 |
|
||||
| `19-memory-trust.png` | Memory Trust — confidence/forget/correct/why-trace | DESIGN_POV §1 |
|
||||
| `19-memory-trust.png` | Memory you can trust (the shelf) | DESIGN_POV §1 |
|
||||
|
||||
> Captures are at the prototype's default viewport and show the prototype's top
|
||||
> "variation" control bar — that chrome is demonstration-only (see SCREENS.md intro).
|
||||
> Open the HTML files for the full, interactive, scrollable, light/dark experience.
|
||||