← Examples Gallery

Alap v3 — Bluesky / AT Protocol

AT Protocol URIs (at://) have no default browser handler — they're a natural fit for Alap's Option of Choice pattern. This example shows two data modes: static entries in allLinks and dynamic results from the :atproto: protocol handler.

Optional: log in for post search

Read-only. Your session token is stored in this browser tab and cleared when you close it. Check "Remember me" to persist across browser sessions.

Two ways to log in:

  1. App password only — if your account doesn't require email verification, entering your handle and app password is all you need.
  2. App password + email code — if your account has email verification enabled, Bluesky will send a confirmation code to your email after the first step. Enter that code to complete login.
Why is this safe?

This demo authenticates directly with Bluesky's official API (bsky.social/xrpc/com.atproto.server.createSession) — the same endpoint the Bluesky app itself uses. Your credentials go straight to Bluesky's servers, never through ours. The email code step is Bluesky's own verification — it confirms the request is really coming from you. You can verify all of this in the source code, and you can revoke your app password at any time.

Static: Option of Choice for Posts

allLinks — no API calls

Each post is hand-curated with entries for different clients and tools. Tags control which destinations appear in the menu.

EFF post — all destinations: client, inspector, raw JSON

Paul Frazee post (clients only) — intersection: .pfrazee_post + .client

All posts (dev tools only) — every post's inspection link

View source
<a class="alap" data-alap-linkitems=".eff_post">EFF post</a>
<a class="alap" data-alap-linkitems=".pfrazee_post + .client">Paul Frazee post (clients only)</a>
<a class="alap" data-alap-linkitems=".atproto_post + .devtool">All posts (dev tools only)</a>

Static: Profiles by Category

allLinks — no API calls

Profiles tagged by category. The expression grammar selects which slice of allLinks to show.

Organizations — EFF, Internet Archive, Creative Commons, Signal

News & Publications — Nature, The Verge, Ars Technica, WIRED, NYT, New Yorker, TechCrunch

Tech Platforms — AT Protocol, Bluesky, GitHub, Node.js, WordPress, Linux Foundation

Everyone (clients) — macro: @all_profiles

View source
<a class="alap" data-alap-linkitems=".orgs + .client">Organizations</a>
<a class="alap" data-alap-linkitems=".news + .client">News & Publications</a>
<a class="alap" data-alap-linkitems=".tech + .client">Tech Platforms</a>
<a class="alap" data-alap-linkitems="@all_profiles">Everyone (clients)</a>

Dynamic: Live Profiles

:atproto: protocol — fetched from the network

The :atproto: handler calls the public Bluesky API and maps the response to AlapLink objects. No auth needed.

AT Protocol team:atproto:profile:atproto.com:

EFF — fetched live from the API

Internet Archive — a different organization

View source
<a class="alap" data-alap-linkitems=":atproto:profile:atproto.com:">AT Protocol team</a>
<a class="alap" data-alap-linkitems=":atproto:profile:eff.org:">EFF</a>
<a class="alap" data-alap-linkitems=":atproto:profile:archive.org:">Internet Archive</a>

Dynamic: Author Feeds

:atproto: protocol — fetched from the network

Recent posts from different accounts. Same handler, different content.

AT Protocol — recent posts:atproto:feed:atproto.com:limit=5:

EFF — recent posts — digital rights and policy

Nature — recent posts — science journal

The Verge — recent posts — tech news

Internet Archive — recent 3 — with limit=3

View source
<a class="alap" data-alap-linkitems=":atproto:feed:atproto.com:limit=5:">AT Protocol — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:eff.org:limit=5:">EFF — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:nature.com:limit=5:">Nature — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:theverge.com:limit=5:">The Verge — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:archive.org:limit=3:">Internet Archive — recent 3</a>

Dynamic: People Search

:atproto: protocol — fetched from the network

Search for accounts by keyword. Results are live.

People: "open source":atproto:people:open_source:limit=5: (alias for "open source")

People: "creative commons" — alias for "creative commons"

People: "atproto" — protocol community

View source
<a class="alap" data-alap-linkitems=":atproto:people:open_source:limit=5:">People: "open source"</a>
<a class="alap" data-alap-linkitems=":atproto:people:creative_commons:limit=5:">People: "creative commons"</a>
<a class="alap" data-alap-linkitems=":atproto:people:atproto:limit=5:">People: "atproto"</a>

// Multi-word queries use aliases defined in the config:
// searches: { open_source: 'open source', creative_commons: 'creative commons' }

Composition: Static + Dynamic

allLinks blended with :atproto: protocol

The same expression grammar works across both data sources. Curated local entries and live API results in one menu.

Org profiles + live EFF posts — static org links merged with 3 recent EFF posts

News outlets, then Nature posts — comma-separated: sorted news profiles, then live science posts

Tech platforms + AT Proto people — curated platforms merged with live people search

View source
<a class="alap" data-alap-linkitems=".orgs + .client | :atproto:feed:eff.org:limit=3:">Org profiles + live EFF posts</a>
<a class="alap" data-alap-linkitems="(.news + .client *sort:label*), (:atproto:feed:nature.com:limit=3:)">News outlets, then Nature posts</a>
<a class="alap" data-alap-linkitems=".tech + .client | :atproto:people:atproto:limit=3:">Tech platforms + AT Proto people</a>

Dynamic: Post Search

:atproto: protocol — requires authentication

Post search (searchPosts) requires a logged-in session. Use the login bar above with an app password.

Log in above to enable these links.

Search: "decentralization":atproto:search:decentralization:limit=5:

Search: "open web" — find posts about the open web

Search: "accessibility" — a11y discussions

Or search for anything:

View source
<a class="alap" data-alap-linkitems=":atproto:search:decentralization:limit=5:">Search: "decentralization"</a>
<a class="alap" data-alap-linkitems=":atproto:search:open_web:limit=5:">Search: "open web"</a>
<a class="alap" data-alap-linkitems=":atproto:search:accessibility:limit=5:">Search: "accessibility"</a>

Full Config

The complete configuration object powering this example. allLinks is static local data, protocols.atproto is the dynamic handler that fetches from the network.

config.ts

Next: Three Sources, One Menu — combine static config, :web:, and :atproto: in a single expression.