homepage session preview chatbox (0.49.0)
- 'See a session' block: an animated chat widget that plays a scripted agent conversation (ship a code change, then expose the preview via Showcase) with typing indicator + message pop-in, looping - shows the core product experience (chatting with/driving an agent) that text alone can't convey; clearly labeled 'a scripted preview of a session' - side copy + 'Browse real agents' CTA; respects prefers-reduced-motion (renders the full convo statically) and cleans up its timers - verified live: widget renders, animates, 0 console errors
This commit is contained in:
parent
3130430874
commit
4a6ee29a2e
@ -4,7 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="theme-color" content="#0e0a14" />
|
<meta name="theme-color" content="#0e0a14" />
|
||||||
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
||||||
<meta name="version" content="0.48.0-seo" />
|
<meta name="version" content="0.49.0-demo" />
|
||||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "amerc-site",
|
"name": "amerc-site",
|
||||||
"version": "0.48.0-seo",
|
"version": "0.49.0-demo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Account from './Account.jsx';
|
|||||||
import TavernGame from './TavernGame.jsx';
|
import TavernGame from './TavernGame.jsx';
|
||||||
import { api } from './api.js';
|
import { api } from './api.js';
|
||||||
|
|
||||||
const RELEASE = '0.48.0-seo';
|
const RELEASE = '0.49.0-demo';
|
||||||
|
|
||||||
const NAV = [
|
const NAV = [
|
||||||
{ id: 'home', label: 'Tavern' },
|
{ id: 'home', label: 'Tavern' },
|
||||||
@ -172,6 +172,38 @@ function FlowDiagram() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const DEMO_SCRIPT = [
|
||||||
|
{ who: 'user', text: 'Add a CSV export button to the orders table.' },
|
||||||
|
{ who: 'agent', text: 'Added an “Export CSV” button to the orders toolbar — it streams /api/orders.csv. Change pushed; your preview is rebuilding now.' },
|
||||||
|
{ who: 'user', text: 'Nice. Expose my local dev server so my client can review it.' },
|
||||||
|
{ who: 'agent', text: 'Live at demo1.you.amerc.ai over HTTPS — tunneled from localhost:3000 through Showcase. Share the link.' },
|
||||||
|
];
|
||||||
|
function ChatDemo() {
|
||||||
|
const [n, setN] = useState(prefersReducedMotion() ? DEMO_SCRIPT.length : 0);
|
||||||
|
const [typing, setTyping] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (prefersReducedMotion()) return;
|
||||||
|
const timers = []; let i = 0;
|
||||||
|
const at = (fn, ms) => timers.push(setTimeout(fn, ms));
|
||||||
|
const next = () => {
|
||||||
|
if (i >= DEMO_SCRIPT.length) { at(() => { setN(0); i = 0; next(); }, 4200); return; }
|
||||||
|
if (DEMO_SCRIPT[i].who === 'agent') { setTyping(true); at(() => { setTyping(false); i += 1; setN(i); at(next, 1000); }, 1400); }
|
||||||
|
else { i += 1; setN(i); at(next, 1200); }
|
||||||
|
};
|
||||||
|
at(next, 700);
|
||||||
|
return () => timers.forEach(clearTimeout);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="cd" role="img" aria-label="Preview of an agent chat session">
|
||||||
|
<div className="cd-head"><span className="cd-ava" aria-hidden="true">💬</span><div className="cd-head-t"><strong>amerc agent</strong><span className="cd-status"><i />online · preview</span></div></div>
|
||||||
|
<div className="cd-body">
|
||||||
|
{DEMO_SCRIPT.slice(0, n).map((m, idx) => <div key={idx} className={`cd-msg ${m.who}`}>{m.text}</div>)}
|
||||||
|
{typing && <div className="cd-msg agent cd-typing" aria-hidden="true"><span /><span /><span /></div>}
|
||||||
|
</div>
|
||||||
|
<div className="cd-foot"><span className="cd-input">Ask the agent…</span><span className="cd-send" aria-hidden="true">➤</span></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
function HomeFeatures({ setRoute }) {
|
function HomeFeatures({ setRoute }) {
|
||||||
return (
|
return (
|
||||||
<section className="hf">
|
<section className="hf">
|
||||||
@ -194,6 +226,16 @@ function HomeFeatures({ setRoute }) {
|
|||||||
<Reveal key={i} className="hf-use" delay={i * 80}><span className="hf-ico-sm">{u.icon}</span><div><strong>{u.title}</strong><p>{u.body}</p></div></Reveal>
|
<Reveal key={i} className="hf-use" delay={i * 80}><span className="hf-ico-sm">{u.icon}</span><div><strong>{u.title}</strong><p>{u.body}</p></div></Reveal>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<h3 className="hf-sub">See a session</h3>
|
||||||
|
<div className="hf-demo">
|
||||||
|
<Reveal className="hf-demo-stage"><ChatDemo /></Reveal>
|
||||||
|
<div className="hf-demo-side">
|
||||||
|
<h4>A hired agent, working for your users.</h4>
|
||||||
|
<p>An embedded chatbox that does real work — ships a code change, then exposes the preview on a public URL through Showcase. Drop it on any page with one <code><script></code> tag.</p>
|
||||||
|
<button className="px-action" onClick={() => setRoute('agents')}>Browse real agents →</button>
|
||||||
|
<span className="hf-demo-note">↑ a scripted preview of a session</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<ActivityFeed />
|
<ActivityFeed />
|
||||||
<div className="hf-cta">
|
<div className="hf-cta">
|
||||||
<button className="px-action" onClick={() => setRoute('agents')}>Browse Agents</button>
|
<button className="px-action" onClick={() => setRoute('agents')}>Browse Agents</button>
|
||||||
|
|||||||
@ -1320,3 +1320,31 @@ button {
|
|||||||
}
|
}
|
||||||
@keyframes fdflowv { from { top: -8px; } to { top: calc(100% + 8px); } }
|
@keyframes fdflowv { from { top: -8px; } to { top: calc(100% + 8px); } }
|
||||||
@media (prefers-reduced-motion: reduce) { .fd-link i { animation: none; opacity: 0; } }
|
@media (prefers-reduced-motion: reduce) { .fd-link i { animation: none; opacity: 0; } }
|
||||||
|
|
||||||
|
/* homepage session preview (0.49) */
|
||||||
|
.hf-demo { display: grid; grid-template-columns: minmax(280px, 380px) 1fr; gap: 28px; align-items: center; }
|
||||||
|
.hf-demo-side h4 { color: #fff; font-size: 18px; margin: 0 0 8px; }
|
||||||
|
.hf-demo-side p { color: #b6a7d4; font-size: 13.5px; line-height: 1.65; margin: 0 0 14px; max-width: 46ch; }
|
||||||
|
.hf-demo-side code { background: #07060c; color: #7fe9ff; padding: 1px 5px; border-radius: 4px; font-size: 12px; }
|
||||||
|
.hf-demo-note { display: block; margin-top: 10px; color: #6f6090; font-size: 11px; font-style: italic; }
|
||||||
|
.cd { background: linear-gradient(180deg, #140e24, #100b1c); border: 1px solid #2c2046; border-radius: 16px; overflow: hidden; box-shadow: 0 16px 40px rgba(0,0,0,0.4); }
|
||||||
|
.cd-head { display: flex; align-items: center; gap: 10px; padding: 12px 14px; background: rgba(39,216,255,0.05); border-bottom: 1px solid #241a36; }
|
||||||
|
.cd-ava { font-size: 17px; width: 32px; height: 32px; display: grid; place-items: center; border-radius: 9px; background: rgba(39,216,255,0.1); border: 1px solid rgba(39,216,255,0.25); }
|
||||||
|
.cd-head-t { display: flex; flex-direction: column; }
|
||||||
|
.cd-head-t strong { color: #fff; font-size: 13px; }
|
||||||
|
.cd-status { color: #8fe9c8; font-size: 11px; display: inline-flex; align-items: center; gap: 5px; }
|
||||||
|
.cd-status i { width: 6px; height: 6px; border-radius: 50%; background: #36f0b0; box-shadow: 0 0 6px #36f0b0; }
|
||||||
|
.cd-body { display: flex; flex-direction: column; justify-content: flex-end; gap: 8px; height: 252px; padding: 14px; overflow: hidden; }
|
||||||
|
.cd-msg { max-width: 84%; padding: 9px 12px; font-size: 12.5px; line-height: 1.5; border-radius: 13px; animation: cd-pop .32s ease-out; }
|
||||||
|
.cd-msg.user { align-self: flex-end; background: linear-gradient(180deg, #2aa7d8, #1f86c4); color: #052230; border-bottom-right-radius: 4px; }
|
||||||
|
.cd-msg.agent { align-self: flex-start; background: #1c1530; color: #e3d9f5; border: 1px solid #2e2348; border-bottom-left-radius: 4px; }
|
||||||
|
@keyframes cd-pop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
|
||||||
|
.cd-typing { display: inline-flex; gap: 4px; padding: 12px 13px; align-self: flex-start; }
|
||||||
|
.cd-typing span { width: 6px; height: 6px; border-radius: 50%; background: #8a7aa8; animation: cd-bounce 1.2s infinite; }
|
||||||
|
.cd-typing span:nth-child(2) { animation-delay: .15s; } .cd-typing span:nth-child(3) { animation-delay: .3s; }
|
||||||
|
@keyframes cd-bounce { 0%,60%,100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-5px); opacity: 1; } }
|
||||||
|
.cd-foot { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-top: 1px solid #241a36; }
|
||||||
|
.cd-input { flex: 1; color: #6f6090; font-size: 12.5px; }
|
||||||
|
.cd-send { color: #27d8ff; font-size: 14px; }
|
||||||
|
@media (max-width: 760px) { .hf-demo { grid-template-columns: 1fr; gap: 18px; } }
|
||||||
|
@media (prefers-reduced-motion: reduce) { .cd-msg { animation: none; } .cd-typing span { animation: none; } }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user