<main class="tl-pen" aria-labelledby="tl-title">
<p class="tl-kicker">TOGETHERLENS · CODEPEN STARTER</p>
<h1 id="tl-title">Which scene should<br><em>we make together?</em></h1>
<p class="tl-copy">Pick a public direction, then pass the same choice to your group. No upload or account is needed for this pen.</p>
<div class="tl-choices" role="group" aria-label="Choose a scene">
<button type="button" data-scene="porch" aria-pressed="false"><span>01</span><strong>Front porch</strong><small>Warm, familiar, easy to repeat.</small></button>
<button type="button" data-scene="rooftop" aria-pressed="false"><span>02</span><strong>Rooftop dusk</strong><small>Graphic light, open space, shared horizon.</small></button>
</div>
<p class="tl-status" data-status aria-live="polite">Choose a direction to unlock the handoff.</p>
<a class="tl-link" data-handoff href="https://togetherlens.app/duel/?utm_source=codepen&utm_medium=template&utm_campaign=codepen_vibe_room&utm_content=pen_fork" aria-disabled="true">Continue with TogetherLens ↗</a>
<p class="tl-credit">Free starter · edit, fork, and publish this pen with the credit intact.</p>
</main>Forkable code · no API
Make the choice
part of the pen.
Open a ready-to-edit CodePen starter for a two-scene group-photo decision. It is useful by itself, easy to fork into a family guide or creative demo, and carries a visible TogetherLens link only after a person chooses to continue.
The handoff tuple is codepen / template / codepen_vibe_room / pen_fork. The store boundary is codepen_vibe_room_handoff.
TOGETHERLENS · PUBLIC SCENES
Which scene should
we make together?
Choose a direction to preview the handoff.
Three portable files
Small enough
to understand.
The pen uses fixed public scenes and one user-triggered link. Fork it, change the copy, and keep the credit visible so the next person can follow the idea without giving TogetherLens access to your site or account.
:root{color-scheme:dark;font-family:Inter,ui-sans-serif,system-ui,sans-serif}*{box-sizing:border-box}.tl-pen{max-width:720px;margin:0 auto;padding:clamp(28px,7vw,72px);color:#f6f1e6;background:radial-gradient(circle at 90% 0%,#3b2c62,transparent 38%),#0c1115;min-height:100vh}.tl-kicker{margin:0;color:#ccff70;font:800 10px/1.2 ui-monospace,monospace;letter-spacing:.15em}.tl-pen h1{margin:22px 0 0;font:500 clamp(42px,8vw,76px)/.9 Georgia,serif;letter-spacing:-.055em}.tl-pen h1 em{color:#c7a7ff;font-weight:400}.tl-copy{max-width:520px;margin:24px 0 0;color:#aeb8b1;font-size:15px;line-height:1.6}.tl-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:34px}.tl-choices button{min-height:180px;padding:18px;border:1px solid #3a4740;border-radius:18px;color:#f6f1e6;background:#141c21;text-align:left;cursor:pointer;transition:transform .18s,border-color .18s,background .18s}.tl-choices button:hover,.tl-choices button:focus-visible{transform:translateY(-3px);border-color:#ccff70;outline:none}.tl-choices button[aria-pressed=true]{border-color:#ccff70;background:#202d25;box-shadow:0 0 0 2px #ccff70 inset}.tl-choices span{display:block;color:#ccff70;font:800 10px ui-monospace,monospace}.tl-choices strong{display:block;margin-top:48px;font:500 27px/.95 Georgia,serif}.tl-choices small{display:block;margin-top:9px;color:#aeb8b1;font-size:11px;line-height:1.35}.tl-status{min-height:20px;margin:18px 0 0;color:#c7a7ff;font-size:12px}.tl-link{display:inline-flex;margin-top:14px;padding:12px 16px;border-radius:999px;color:#10170d;background:#ccff70;font-weight:800;text-decoration:none;pointer-events:none;opacity:.42}.tl-link[data-ready=true]{pointer-events:auto;opacity:1}.tl-credit{margin:28px 0 0;color:#7e8b83;font-size:10px;line-height:1.5}@media(max-width:560px){.tl-choices{grid-template-columns:1fr}.tl-choices button{min-height:145px}.tl-choices strong{margin-top:26px}}const handoff = document.querySelector('[data-handoff]');
const status = document.querySelector('[data-status]');
document.querySelectorAll('[data-scene]').forEach((button) => {
button.addEventListener('click', () => {
document.querySelectorAll('[data-scene]').forEach((candidate) => candidate.setAttribute('aria-pressed', String(candidate === button)));
handoff.dataset.ready = 'true';
handoff.setAttribute('aria-disabled', 'false');
status.textContent = button.querySelector('strong').textContent + ' selected. Share the pen or continue when the group agrees.';
});
});Publisher boundary
A forkable idea,
not a hidden hook.
- 01No host-page accessThe starter never reads DOM, storage, contacts, camera, or account data.
- 02Useful without usThe two-scene choice works as a standalone CodePen demo.
- 03Explicit next stepThe TogetherLens link unlocks only after a person chooses a scene.
When a group is ready
Turn the fork
into a photo.
Choose a store below. Store clicks are consent-gated and retain the CodePen campaign separately from generic resource traffic. A click is not evidence of an install or subscription.
CodePen publisher cohort
Choose the store your group uses.Keep the visible credit and the exact handoff URL when publishing a fork.