Skip to content
← Public packages

@kentcdodds/invisible-software

Invisible software: a phone-only step-through demo plus a chart of AI agent benchmark progress.

FollowForkOpen app

src/slides/06-intent-conflict.html

212 lines · 12.6 KB · HTML
Raw
<section class="slide uses-vc-app uses-chat" data-label="6" data-opener="[1]" data-duration="22" data-steps="[[0.4,1.8],[2.75,3.9],[5.15,7.8],[8.6,9],[9.8,11],[11.4,11.8],[12.1,12.5],[13.15,14.65],[15.85,16.75],[17.35,18.1],[18.65,19.7]]" data-human="[2,3,8,9,10,11]">
<style>
@keyframes breathe-intent-conflict { 0%, 100% { transform: scale(0.7); opacity: 0.55; } 50% { transform: scale(1); opacity: 1; } }
@scope {
	.phone { left: 1150px; top: 102px; transform: scale(1.1); }
	.caption { left: 160px; width: 820px; }
	.sub b { color: var(--kody-text); font-weight: 650; }
	.lock { z-index: 1; }
	.notif { top: 318px; transition: none; z-index: 3; }
	.notif .n-body { font-size: 15.5px; }
	.lock-blur { position: absolute; inset: 0; background: rgb(30 20 50 / 0.35); backdrop-filter: blur(16px); opacity: 0; z-index: 2; }
	.notif-actions { z-index: 3; opacity: 0; }
	.notif-actions .yes { font-weight: 600; color: #0a84ff; }
	.chat { z-index: 20; opacity: 0; }
	.chat .msg.bot { font-size: 16.5px; }
	.work { align-self: flex-start; width: 316px; border-radius: 22px; background: #f0f0f2; padding: 13px 16px 14px; font-family: var(--ios); }
	.work-head { display: flex; align-items: center; gap: 9px; font: 650 15.5px/1 var(--ios); color: #111; }
	.work-head .orb { width: 11px; height: 11px; border-radius: 50%; background: #111; animation: breathe-intent-conflict 1.1s ease-in-out infinite; }
	.work-head .orb.done { animation: none; background: var(--kody-green); transform: none; opacity: 1; }

	.wl { display: flex; align-items: center; gap: 9px; margin-top: 10px; font: 500 14px/1.25 var(--ios); white-space: nowrap; color: #3c3c43; opacity: 0; transform: translateY(6px); }
	.wl .st { width: 18px; height: 18px; flex: none; display: grid; place-items: center; }
	.wl .spin { width: 15px; height: 15px; border-radius: 50%; border: 2.2px solid #c9c9cf; border-top-color: #111; animation: spin .8s linear infinite; }
	.wl .ok { width: 18px; height: 18px; border-radius: 50%; background: var(--kody-green); color: #fff; display: grid; place-items: center; }
	.wl .ok svg { width: 11px; height: 11px; }
	.wl.fin { color: #8a8a8e; }
	.safari { z-index: 30; }
	.safari-body { background: var(--vc-cream); }
	.pub .book-now { position: relative; }
	.pub .new { position: absolute; right: 12px; top: -9px; padding: 4px 8px; border-radius: 999px; background: #1c2230; color: #fff; font: 700 10.5px/1 var(--ios); letter-spacing: .06em; }
	.pub .dep-note { margin-top: 12px; display: flex; align-items: center; justify-content: center; gap: 7px; font: 500 13px/1.2 var(--ios); color: #6d6a63; }
	.pub .dep-note img { width: 15px; height: 15px; }
	.dim { position: absolute; inset: 0; z-index: 14; background: rgb(20 20 30 / 0.35); opacity: 0; }
	.sheet { position: absolute; left: 0; right: 0; bottom: 0; z-index: 15; background: #fff; border-radius: 22px 22px 0 0; padding: 10px 16px 22px; box-shadow: 0 -10px 40px rgb(0 0 0 / 0.2); font-family: var(--ios); color: var(--vc-ink); transform: translateY(110%); }
	.sheet .grab { width: 38px; height: 5px; border-radius: 3px; background: #d8d4cc; margin: 0 auto 14px; }
	.sheet h3 { font: 750 21px/1.1 var(--ios); letter-spacing: -0.02em; display: flex; justify-content: space-between; align-items: center; }
	.sheet h3 small { font: 500 13px/1 var(--ios); color: #8a847a; }
	.sheet .slot.pick { background: var(--vc-brass); color: #fff; border: 1.5px solid var(--vc-brass); }
	.sheet .svc-line { margin-top: 12px; display: flex; justify-content: space-between; font: 600 14.5px/1 var(--ios); color: #5b564c; }
	.dep { margin-top: 14px; display: flex; align-items: center; gap: 10px; padding: 12px; border-radius: 14px; background: #f5f3ff; border: 1px solid #e3defe; font: 500 14px/1.3 var(--ios); color: #4b4592; }
	.dep .s-ic { width: 30px; height: 30px; border-radius: 8px; background: #635bff; display: grid; place-items: center; flex: none; }
	.dep .s-ic img { width: 18px; height: 18px; filter: brightness(0) invert(1); }
	.dep b { color: #1c2230; display: block; font-size: 15px; }
	.paybtn { margin-top: 12px; height: 52px; border-radius: 14px; background: #635bff; color: #fff; display: flex; align-items: center; justify-content: center; gap: 8px; font: 650 17px/1 var(--ios); }
	.paybtn.done { background: #1f9d55; }
	.paybtn .spin { width: 18px; height: 18px; border-radius: 50%; border: 2.4px solid rgb(255 255 255 / .35); border-top-color: #fff; animation: spin .8s linear infinite; }
}
</style>
<div class="stage-pattern"></div>
<div class="bug"><img src="assets/kody-mark.png">Kody<span class="dom">kody.codes</span></div>

<div class="caption">
	<div class="cap" style="animation: capIn .8s cubic-bezier(.22,1,.36,1) .4s both, capOut .5s ease 5.7s forwards">
		<div class="kicker">Subscribed</div>
		<div class="headline">Max<br><em>republishes</em></div>
		<div class="sub">Victoria subscribed to his package. Grok Bot checks his change against <b>what she wants</b>.</div>
	</div>
	<div class="cap" style="animation: capIn .8s cubic-bezier(.22,1,.36,1) 6.3s both, capOut .5s ease 13.6s forwards">
		<div class="kicker">Intent, not just code</div>
		<div class="headline">His link.<br>Her <em>deposits</em>.</div>
		<div class="sub">Grok Bot brings in the Book now link and keeps her Stripe flow.</div>
	</div>
	<div class="cap" style="animation: capIn .8s cubic-bezier(.22,1,.36,1) 14.2s both">
		<div class="kicker">What her clients see</div>
		<div class="headline">Clients book.<br>Deposits <em>still land</em>.</div>
		<div class="sub">The best of both apps, without a merge conflict.</div>
	</div>
</div>

<div class="phone"><div class="screen">
	<div class="island"></div>

	<div class="lock" id="lock">
		<div class="statusbar light" data-time="6:12"></div>
		<div class="lock-date">Wednesday, October 14</div>
		<div class="lock-time">6:12</div>
		<div class="lock-blur" id="blur"></div>
		<div class="notif" id="notif">
			<div class="app-ic gb-icon"><img src="assets/grokbot.svg"></div>
			<div><div class="n-head">Grok Bot<time>now</time></div>
			<div class="n-body">Max changed booking to his own scheduler. Your clients pay deposits through Stripe. Bring in his Book now link but keep your deposit flow?</div></div>
		</div>
		<div class="notif-actions" id="acts"><div class="yes" id="yes">Yes</div><div id="no">No</div></div>
		<div class="lock-btn l" data-icon="flash"></div>
		<div class="lock-btn r" data-icon="camera"></div>
		<div class="home-ind light"></div>
	</div>

	<div class="chat" id="chat">
		<div class="statusbar" data-time="6:12"></div>
		<div class="chat-head">
			<div class="round-btn back" data-icon="chevL"></div>
			<div class="head-pill"><div class="av gb-icon"><img src="assets/grokbot.svg"></div>Grok Bot</div>
			<div class="round-btn" data-icon="dots"></div>
		</div>
		<div class="msgs">
			<div class="stamp">Today 6:12 AM</div>
			<div class="msg bot">Max changed booking to his own scheduler. Your clients pay deposits through Stripe. Bring in his Book now link but keep your deposit flow?</div>
			<div class="row me" style="--d:6.7s"><div class="msg me">Yes</div></div>
			<div class="row" style="--d:7.2s"><div class="work">
				<div class="work-head"><span class="orb" id="orb"></span><span id="workTitle">Grok Bot is working</span></div>
				<div class="wl" data-t0="7.5" data-t1="8.7"><span class="st"></span>Bringing in Max's Book now link…</div>
				<div class="wl" data-t0="8.7" data-t1="9.9"><span class="st"></span>Keeping your Stripe deposits…</div>
				<div class="wl" data-t0="9.9" data-t1="11.0"><span class="st"></span>Publishing your update…</div>
			</div></div>
			<div class="row" style="--d:11.4s"><div class="msg bot">Done! Clients now tap Book now to pick a time, and every booking still takes a $20 deposit through Stripe.</div></div>
			<div class="row" style="--d:12.1s"><div class="linkcard" id="linkCard">
				<div class="lc-img">
					<div class="app-head"><img class="av-img" src="assets/victoria.jpg"><div><h1>Victoria's Chair</h1><p>Book a cut</p></div></div>
					<div class="mini-btn">Book now ↗</div>
				</div>
				<div class="lc-meta"><b>Victoria's Chair · Book a cut</b><span><img src="assets/kody-mark.png" style="width:15px;height:15px">victoria.kody.run</span></div>
			</div></div>
		</div>
		<div class="composer">
			<div class="round-btn plus" data-icon="plus"></div>
			<div class="field"><span class="ph">Ask Grok Bot</span><span class="mic" data-icon="mic"></span><span class="go" data-icon="wave"></span></div>
		</div>
		<div class="home-ind"></div>
	</div>

	<div class="safari" id="saf">
		<div class="statusbar" data-time="6:13"></div>
		<div class="safari-top" data-url="victoria.kody.run"></div>
		<div class="safari-body">
			<div class="pub">
				<div class="hero"><img class="av-img" src="assets/victoria.jpg"><h1>Victoria's Chair</h1><p>Fresh cuts · fades · beard work<br>Open Thursday · 2 slots left</p></div>
				<div class="book-now" id="bookNow">Book now <span data-icon="arrowUR"></span><span class="new">NEW</span></div>
				<div class="dep-note"><img src="assets/stripe.svg">$20 deposit holds your spot</div>
				<div class="card svc">
					<div><span>Classic cut<small>45 min</small></span><b>$35</b></div>
					<div><span>Skin fade<small>50 min</small></span><b>$40</b></div>
					<div><span>Beard trim<small>20 min</small></span><b>$20</b></div>
				</div>
			</div>
			<div class="dim" id="dim"></div>
			<div class="sheet" id="sheet">
				<div class="grab"></div>
				<h3>Book with Victoria <small>Thursday, Oct 15</small></h3>
				<div class="slots"><div class="slot">9:00</div><div class="slot taken">10:30</div><div class="slot taken">1:00</div><div class="slot" id="pick">3:30</div></div>
				<div class="svc-line"><span>Classic cut · 45 min</span><span>$35</span></div>
				<div class="dep"><span class="s-ic"><img src="assets/stripe.svg"></span><div><b>$20 deposit holds your spot</b>Paid securely with Stripe</div></div>
				<div class="paybtn" id="pay">Pay $20 deposit</div>
			</div>
		</div>
		<div class="safari-bottom"></div>
	</div>
	<div class="home-ind" style="z-index:60;opacity:0" id="safHome"></div>
</div></div>
<div class="stage-vignette"></div>
<script>
deck.slide(({ root, onTime, tapOn, openFrom }) => {
	const $ = (s) => root.querySelector(s)
	const T_CHAT = 5.8, T_OPEN = 13.8
	tapOn('#notif', 2.9, 1.0)
	tapOn('#yes', 5.3)
	tapOn('#linkCard', 13.3)
	tapOn('#bookNow', 16.0)
	tapOn('#pick', 17.5)
	tapOn('#pay', 18.8)
	openFrom($('#chat'), '#notif', T_CHAT)
	openFrom($('#saf'), '#linkCard', T_OPEN)
	const notif = $('#notif'), acts = $('#acts'), blur = $('#blur')
	const lines = [...root.querySelectorAll('.wl')]
	onTime((t) => {
		const a = ease(prog(t, 1.2, 1.8))
		const x = easeInOut(prog(t, 3.3, 3.75))
		const c = easeInOut(prog(t, 5.6, 5.9))
		notif.style.opacity = a * (1 - c)
		notif.style.transform = `translateY(${(1 - a) * 60 + x * -40}px) scale(${(0.92 + 0.08 * a) * (1 + x * 0.03)})`
		blur.style.opacity = x * (1 - c)
		acts.style.top = 318 + notif.offsetHeight + 10 + 'px'
		acts.style.opacity = x * (1 - c)
		acts.style.transform = `translateY(${-40 + (1 - x) * 20}px) scale(${0.95 + 0.05 * x})`
		$('#yes').style.background = t >= 5.35 && t < 5.9 ? 'rgb(0 0 0 / 0.08)' : ''
		$('#lock').style.visibility = t > T_CHAT + 0.7 ? 'hidden' : ''
		$('#chat').style.visibility = t > T_OPEN + 0.7 ? 'hidden' : ''
		$('#safHome').style.opacity = t >= T_OPEN + 0.6 ? 1 : 0

		for (const l of lines) {
			const t0 = +l.dataset.t0, t1 = +l.dataset.t1
			const i = ease(prog(t, t0, t0 + 0.3))
			l.style.opacity = i
			l.style.transform = `translateY(${(1 - i) * 6}px)`
			const done = t >= t1
			l.classList.toggle('fin', done)
			const st = l.firstElementChild, want = done ? 'ok' : 'spin'
			if (st.__s !== want) { st.__s = want; st.innerHTML = done ? `<span class="ok">${icon.check}</span>` : '<span class="spin"></span>' }
		}
		const finished = t >= 11.0
		$('#orb').classList.toggle('done', finished)
		$('#workTitle').textContent = finished ? 'Update published' : 'Grok Bot is working'

		const pr = $('.url-progress'), lp = prog(t, T_OPEN, T_OPEN + 0.8)
		pr.style.width = lp * 100 + '%'; pr.style.opacity = lp > 0 && lp < 1 ? 1 : 0
		const glow = prog(t, 15.95, 16.45)
		$('#bookNow').style.boxShadow = glow > 0 && glow < 1 ? `0 0 0 ${4 + glow * 8}px rgb(176 129 63 / ${0.45 * (1 - glow)}), 0 6px 16px rgb(176 129 63 / 0.35)` : ''

		const sh = easeInOut(prog(t, 16.3, 16.75))
		$('#sheet').style.transform = `translateY(${(1 - sh) * 110}%)`
		$('#dim').style.opacity = sh
		$('#pick').classList.toggle('pick', t >= 17.65)
		const pay = $('#pay'), ps = t < 18.95 ? 'a' : t < 19.7 ? 'b' : 'c'
		if (pay.__s !== ps) {
			pay.__s = ps
			pay.classList.toggle('done', ps === 'c')
			pay.innerHTML = ps === 'a' ? 'Pay $20 deposit' : ps === 'b' ? '<span class="spin"></span>Paying with Stripe…' : `${icon.check}Booked Thursday 3:30 · $20 paid`
		}
	})
})
</script>
</section>