Turn your existing site
into an AI-native site

No jarring sidebar, no clunky AI integration — your original interface stays, while the user experience gets better.

Search commands or page…
Ctrl+K
Settings
/theme Toggle light / dark mode
/language English · 繁體中文
Commands
customer: Find a customer
/billing Open billing
Ask AI anything

Every feature, behind one palette.

Press Ctrl+K. Your registered commands sit alongside Ask AI in one list — prefix routing for `/command`, `@entity`, `order:`, `#tag`.

Theme via CSS variables, scripts and prompts via the Skill SDK, or wire existing features in as palette items. Zero built-in commands — what shows up is yours.

An agent that operates the page, not a sidebar chatbot.

DOM-grounded loop in the user's tab. The LLM picks one action at a time; the subtitle bar narrates each step; the agent asks back when ambiguous.

Hold Space for voice. The transcript optionally cleans up via LLM before going to the agent. Provider is your call — OpenAI, Google AI Studio, or a server-side proxy.

"Set the chart to last quarter and download CSV"
1 navigate /analytics
2 click the last-quarter range button
3 highlight the export button
4 click confirm download
done CSV downloaded · subtitle: done

Select text. AI without leaving the input.

Highlight text in any input or contenteditable — a floating toolbar appears next to the selection. Pick an action; the result streams back in place.

Actions are customizable, layout can be two-column, optional keyboard shortcuts. IME-aware so Chinese / Japanese / Korean composition never accidentally triggers it.

Long-press, hold, release — gestures you already know.

A · VOICE

Hold Space

Hold Space anywhere — the subtitle bar shows Listening. Release to send. Inside an input → transcript fills it. Anywhere else → goes to the agent.

Demo uses the browser Web Speech API; production hosts swap in Whisper / Deepgram / AssemblyAI via a one-line `transcribe(audio)` callback.

B · DWELL

Long-press anything

Long-press any element ~1s — a frame pins around it. Next Ctrl+K opens the palette with that element as context. Visual elements ship with an auto screenshot.

C · /INTRODUCE

/introduce tour

Script Skills are declarative tours: `page` + `subtitle` + `action`, Space to advance. Write onboarding once, replay any time.

D · SCREENSHOT

Drag a screenshot

Camera in the palette → drag a rectangle on the page. The capture attaches to your next Ask AI / agent question.

Read the signal. Ask the right question. Customer-service in one bar.

The agent watches page signals (scroll, dwell, time-on-page) and surfaces an offer in the subtitle bar when conditions match. Yes / no via Space; multi-choice via 1-9 plus a free-text Other slot.

Order shipped → "want the tracking?". Lingering on returns → list common actions. Whole exchange stays in the subtitle bar — no popup, no layout shift.

SUBTITLE · YES / NO
Your Monday order just shipped — want me to pull the tracking?
Space to accept · double-tap Space to reject · Esc to cancel
intent: proactive_accepted, action: 'track_order', via: 'voice'
SUBTITLE · MULTI-CHOICE
How should I handle this return?
digit to pick · click works too · esc cancels · type into Other to free-text
intent: agent_choice, value: 'create_rma', via: 'click'
palette_activated
Which command was opened
voice_captured
The transcript the user spoke
proactive_response
Proactive offer — yes / no / dismiss
agent_pause_decision
Continue or stop every time the agent paused
selection_used
Which region the user pinned via Dwell
agent_feedback
Satisfied or not, at the end of every run

Every yes / no is a signal. The dashboard writes itself.

Every accept, reject, choice, voice transcript, and Dwell pin emits a typed event. Subscribe once — who wanted a refund, who wanted to upgrade, which offers land.

Direct asking, recorded answers — no inferring from clicks. Built-in dashboard for charts, or pipe to Mixpanel / Amplitude / your own BI.

Three lines. Themable. Keys stay server-side.

One npm package, three lines to wire up. 28 CSS variables for theming. API keys go through a Worker and stay on the server — the client never sees them.

npm install @perhapxin/dddk

import { DotDotDuck, OpenAIProvider } from '@perhapxin/dddk';
import '@perhapxin/dddk/styles.css';

new DotDotDuck({
  siteName: 'YourSaaS',
  llm: new OpenAIProvider({ apiKey: '...' }),
}).mount();

Try it on this page. Press Ctrl+K.