252 lines
9.6 KiB
JavaScript
252 lines
9.6 KiB
JavaScript
// The Wall — recreates the moment the vibe dies. Faux chat from a "generic" AI
|
|
// coding tool that hands back a homework list. Ends on the punchline.
|
|
|
|
function Wall() {
|
|
return (
|
|
<section className="section wall" id="the-wall">
|
|
<style>{`
|
|
.wall { padding-block: clamp(60px, 9vh, 110px); }
|
|
.wall-head { text-align: center; max-width: 760px; margin: 0 auto 56px; }
|
|
.wall-title {
|
|
font-size: clamp(36px, 4.8vw, 64px);
|
|
font-weight: 500; letter-spacing: -0.025em; line-height: 1.02;
|
|
text-wrap: balance;
|
|
}
|
|
.wall-title em {
|
|
font-style: normal;
|
|
color: var(--accent);
|
|
text-shadow: 0 0 30px var(--accent-glow);
|
|
}
|
|
.wall-sub {
|
|
margin-top: 20px;
|
|
color: var(--fg-mute);
|
|
font-size: 17px;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
/* Faux app window */
|
|
.window {
|
|
max-width: 880px; margin: 0 auto;
|
|
position: relative;
|
|
border-radius: 16px;
|
|
background: oklch(0.165 0.008 60 / 0.85);
|
|
border: 1px solid var(--hairline);
|
|
box-shadow: 0 30px 80px -20px oklch(0 0 0 / 0.6);
|
|
overflow: hidden;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
.window-bar {
|
|
display: flex; align-items: center; gap: 14px;
|
|
padding: 11px 14px;
|
|
background: oklch(0.20 0.009 60 / 0.85);
|
|
border-bottom: 1px solid var(--hairline);
|
|
font-family: var(--font-mono);
|
|
font-size: 12px;
|
|
color: var(--fg-mute);
|
|
}
|
|
.traffic { display: flex; gap: 7px; }
|
|
.traffic i {
|
|
width: 11px; height: 11px; border-radius: 50%;
|
|
background: oklch(0.40 0.01 60);
|
|
}
|
|
.window-name {
|
|
margin-left: 8px; color: var(--fg-faint);
|
|
letter-spacing: 0.02em;
|
|
}
|
|
.window-tag {
|
|
margin-left: auto;
|
|
padding: 2px 8px; border-radius: 4px;
|
|
background: oklch(0.25 0.01 60); color: var(--fg-faint);
|
|
font-size: 11px;
|
|
}
|
|
|
|
.chat { padding: 24px; display: flex; flex-direction: column; gap: 16px; }
|
|
.msg {
|
|
display: flex; gap: 12px; align-items: flex-start;
|
|
font-size: 14.5px; line-height: 1.55;
|
|
}
|
|
.avatar {
|
|
width: 26px; height: 26px; border-radius: 7px;
|
|
display: grid; place-items: center;
|
|
font-family: var(--font-mono); font-size: 11px; font-weight: 600;
|
|
flex-shrink: 0;
|
|
}
|
|
.avatar.user { background: oklch(0.28 0.01 60); color: var(--fg-dim); }
|
|
.avatar.ai { background: oklch(0.30 0.02 250); color: oklch(0.85 0.06 250); }
|
|
.msg-body { flex: 1; min-width: 0; }
|
|
.msg-name {
|
|
font-family: var(--font-mono);
|
|
font-size: 11px;
|
|
color: var(--fg-faint);
|
|
letter-spacing: 0.04em;
|
|
margin-bottom: 3px;
|
|
text-transform: uppercase;
|
|
}
|
|
.msg p { margin: 0; color: var(--fg-dim); }
|
|
.msg.user .msg-body p { color: var(--fg); }
|
|
|
|
.homework-intro { color: var(--fg-dim); }
|
|
.homework-list {
|
|
list-style: none; padding: 0; margin: 12px 0 0;
|
|
display: flex; flex-direction: column; gap: 8px;
|
|
counter-reset: hw;
|
|
}
|
|
.homework-list li {
|
|
counter-increment: hw;
|
|
display: flex; gap: 12px; align-items: flex-start;
|
|
padding: 12px 14px;
|
|
background: oklch(0.20 0.009 60);
|
|
border: 1px solid var(--hairline);
|
|
border-radius: 10px;
|
|
color: var(--fg-dim);
|
|
font-size: 13.5px;
|
|
transition: opacity .3s, filter .3s;
|
|
}
|
|
.homework-list li::before {
|
|
content: counter(hw, decimal-leading-zero);
|
|
font-family: var(--font-mono);
|
|
font-size: 11px;
|
|
color: var(--fg-faint);
|
|
padding: 1px 6px;
|
|
background: oklch(0.16 0.008 60);
|
|
border-radius: 4px;
|
|
flex-shrink: 0;
|
|
}
|
|
.homework-list li .ext {
|
|
margin-left: auto;
|
|
font-family: var(--font-mono);
|
|
font-size: 11px;
|
|
color: var(--fg-faint);
|
|
padding: 1px 7px;
|
|
border: 1px solid var(--hairline);
|
|
border-radius: 4px;
|
|
flex-shrink: 0;
|
|
}
|
|
.homework-list li b { color: var(--fg); font-weight: 500; }
|
|
|
|
/* desaturate the bottom of the list to convey overload */
|
|
.homework-list li:nth-child(4) { opacity: .82; }
|
|
.homework-list li:nth-child(5) { opacity: .65; }
|
|
.homework-list li:nth-child(6) { opacity: .48; filter: blur(.2px); }
|
|
.homework-list li:nth-child(7) { opacity: .34; filter: blur(.4px); }
|
|
.homework-list li:nth-child(8) { opacity: .22; filter: blur(.7px); }
|
|
.homework-fade {
|
|
margin-top: -10px; padding-top: 30px;
|
|
background: linear-gradient(180deg, transparent, oklch(0.165 0.008 60 / 0.85));
|
|
font-family: var(--font-mono);
|
|
font-size: 11px;
|
|
color: var(--fg-faint);
|
|
text-align: center;
|
|
}
|
|
|
|
.typing {
|
|
display: inline-flex; gap: 3px; align-items: center;
|
|
padding: 4px 0;
|
|
color: var(--fg-mute);
|
|
}
|
|
.typing i {
|
|
width: 5px; height: 5px; border-radius: 50%; background: var(--fg-mute);
|
|
animation: bounce 1.2s infinite ease-in-out;
|
|
}
|
|
.typing i:nth-child(2) { animation-delay: .15s; }
|
|
.typing i:nth-child(3) { animation-delay: .3s; }
|
|
@keyframes bounce {
|
|
0%, 80%, 100% { transform: translateY(0); opacity: .5; }
|
|
40% { transform: translateY(-3px); opacity: 1; }
|
|
}
|
|
|
|
/* The punchline beat */
|
|
.punchline {
|
|
margin-top: 56px;
|
|
text-align: center;
|
|
}
|
|
.punchline-text {
|
|
font-size: clamp(28px, 3.4vw, 42px);
|
|
font-weight: 500; letter-spacing: -0.022em;
|
|
color: var(--fg-mute);
|
|
line-height: 1.2; text-wrap: balance;
|
|
}
|
|
.punchline-text em {
|
|
font-style: italic;
|
|
color: var(--fg);
|
|
}
|
|
.punchline-divider {
|
|
width: 1px; height: 56px;
|
|
background: linear-gradient(180deg, transparent, var(--hairline), transparent);
|
|
margin: 0 auto 28px;
|
|
}
|
|
`}</style>
|
|
|
|
<div className="wrap">
|
|
<div className="wall-head">
|
|
<Eyebrow>The wall</Eyebrow>
|
|
<h2 className="wall-title" style={{ marginTop: 18 }}>
|
|
Every other tool stops <em>right here</em>.
|
|
</h2>
|
|
<p className="wall-sub">
|
|
You built it. It works on your laptop. Then the chat hands you a list.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="window">
|
|
<div className="window-bar">
|
|
<div className="traffic"><i/><i/><i/></div>
|
|
<span className="window-name">untitled-project · main</span>
|
|
<span className="window-tag">generic ai coder · chat</span>
|
|
</div>
|
|
|
|
<div className="chat">
|
|
<div className="msg user">
|
|
<div className="avatar user">YOU</div>
|
|
<div className="msg-body">
|
|
<div className="msg-name">You · just now</div>
|
|
<p>okay it works!! how do i put this online so my customers can use it?</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="msg ai">
|
|
<div className="avatar ai">AI</div>
|
|
<div className="msg-body">
|
|
<div className="msg-name">Generic AI · just now</div>
|
|
<p className="homework-intro">
|
|
Great job 🎉 Your app is running locally. To take it live, you'll need to set a few things up first:
|
|
</p>
|
|
<ol className="homework-list">
|
|
<li><b>Sign up for Supabase</b> and create a project for your database.<span className="ext">↗ external</span></li>
|
|
<li><b>Configure authentication</b> with Supabase Auth or Clerk — pick one.<span className="ext">↗ external</span></li>
|
|
<li><b>Create a GitHub repo</b>, commit your code, and push it.<span className="ext">↗ external</span></li>
|
|
<li><b>Deploy to Vercel</b>: connect repo, configure framework preset.<span className="ext">↗ external</span></li>
|
|
<li><b>Add environment variables</b> for your API keys and DB url in the Vercel dashboard.<span className="ext">↗ external</span></li>
|
|
<li><b>Set up DNS</b> for your custom domain and verify nameservers with your registrar.<span className="ext">↗ external</span></li>
|
|
<li><b>Configure SSL / TLS certificates</b> for HTTPS (or use Vercel's automatic provisioning).<span className="ext">↗ external</span></li>
|
|
<li><b>Set up Stripe</b> if you want to take payments, and configure webhooks.<span className="ext">↗ external</span></li>
|
|
</ol>
|
|
<div className="homework-fade">↓ 23 more steps</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="msg user">
|
|
<div className="avatar user">YOU</div>
|
|
<div className="msg-body">
|
|
<div className="msg-name">You · now</div>
|
|
<p style={{ color: "var(--fg-mute)" }}>
|
|
<span className="typing"><i/><i/><i/></span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="punchline">
|
|
<div className="punchline-divider"></div>
|
|
<p className="punchline-text">
|
|
And just like that — <em>the vibe is gone.</em>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
Object.assign(window, { Wall });
|