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.

Preview the handoff ↗

The handoff tuple is codepen / template / codepen_vibe_room / pen_fork. The store boundary is codepen_vibe_room_handoff.

codepen.io / your-forkHTML · CSS · JS

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.

HTML
<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>
CSS
: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}}
JS
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.