Examples
Four complete apps, a family of packages, and a large imported library. For each you can:
- run it on the docs site, under its own path (
tcm start --base, or a static site). The notes and polls apps reset to empty every six hours. - browse it as a codebase, in a forge of its own: definitions, history and releases (code).
- build it yourself: download it and run its
setup.sh, which builds it into a fresh codebase with thetcmon yourPATH(or the command line inTCM).
polls: a live polling app
Run it (open it in two windows to see the votes arrive)
curl -fsSL https://tcm.codes/docs/examples/polls.tar.gz | tar xz
polls/setup.sh /tmp/polls # builds the codebase there and runs its tests
cd /tmp/polls && tcm dev polls.main # or open /tmp/polls in VS Code with the tcm-ts extension
A small app that uses most of what tcm does, with nothing saying what runs where:
model.ts(examples/polls/model.ts)- plain functions (
tally,leader,chart) that run anywhere; tests; sample data server.ts(examples/polls/server.ts)- the server library tcm ships (
setup.shmounts it withtcm lib add tcm server): typed tables, sessions, a rate limit, a background job that announces the winner when a poll closes, a nightly schedule, a streaming function for live results, and a server test usingwithRequest ui.ts(examples/polls/ui.ts)- browser code calling the server like local functions, including
for awaitover the live stream playground.ts(examples/polls/playground.ts)- the scratch file you start with: watch expressions over the model, and a definition to change
Its definitions are documented with links and evaluated examples
(tcm docs polls.chart); polls.README is the namespace's front page.
setup.sh adds the three files to a new codebase, then deletes them: the code lives in the codebase from then on.
Browse it with tcm ls polls and tcm view polls.vote, or in VS Code's Codebase sidebar. tcm view shows where
each runs: polls.chart anywhere, polls.vote on the server (callable from the browser by hash), polls.main in
the browser.
notes: React server components
curl -fsSL https://tcm.codes/docs/examples/notes.tar.gz | tar xz
notes/setup.sh /tmp/notes # builds the codebase there and runs its tests
cd /tmp/notes && tcm dev notes.App # or ▶ Start in VS Code's Apps view
A notes app in the style of React's Server Components demo, with no "use client" or "use server". tcm infers
where each component renders from what it uses (React):
model.ts(examples/notes/model.ts)- plain functions (
excerpt,matches,ago) that run anywhere; tests; sample notes markdown.tsx(examples/notes/markdown.tsx)- a markdown renderer and its
Markdowncomponent: plain elements, so one hash renders on the server in a note's page and in the browser in the editor's live preview server.ts(examples/notes/server.ts)- the
notestable and the server functions that change it (the server library, mounted bysetup.shwithtcm lib add tcm server), with a test styles.css(examples/notes/styles.css)- the page's look: a stylesheet kept in the codebase as written, which
ui.tsximports like a definition (its text) and links to with<Stylesheet> ui.tsx(examples/notes/ui.tsx)- server components (
NoteList,NotePreview: async, they read the table), browser components (App,NoteEditor,SidebarNote: state and handlers), the URL as state (the react library's location, mounted bysetup.shwithtcm lib add tcm react), and a browser test of the editor playground.tsx(examples/notes/playground.tsx)- the scratch file you start with: watch expressions, including a component rendered to HTML
tcm dev notes.App prints the split: three server components fetched by hash, the browser components they send by
hash, and the server functions the browser calls. The first paint, links to notes included, is rendered on the
server and hydrated in the browser. Saving a note refreshes the sidebar by itself: after a server function call,
server components fetch their trees again.
userinput: an AT Protocol client
Run it (signing in writes to your own repository, as userinput.app does)
curl -fsSL https://tcm.codes/docs/examples/userinput.tar.gz | tar xz
userinput/setup.sh /tmp/userinput # builds the codebase there and runs its tests
cd /tmp/userinput && tcm dev userinput.app.App # then sign in with your Bluesky handle
A client for userinput.app, feedback boards on the AT Protocol: post ideas into a space, vote, reply in threads, and, as a space's owner or moderator, set statuses, pin, hide, lock and ban. It has no server of its own. Every record lives in its author's repository; the app reads them through userinput.app's index of boards, or through Constellation (an index of which records point at which), and signs in with AT Protocol OAuth from the browser. It's the largest example (about two hundred definitions, React and React Aria), styled like Apple's apps:
model.ts(examples/userinput/model.ts)- the records (userinput.app's lexicons) as types,
at://URIs, and the services it talks to network.ts(examples/userinput/network.ts)- reading the network politely: a couple of dozen requests at a time per service, backing off when asked, each read once
rules.ts(examples/userinput/rules.ts)- what the records add up to: a status counts only from the space's moderators, an edit only from its author; scores, threads, sorting; tested
data.ts(examples/userinput/data.ts)- each page's data: a board or discussion from userinput.app's index (its app view) in one request, with your votes and new posts from your repository, which has them first; or, when the index can't say, assembled from records in many repositories
session.ts(examples/userinput/session.ts),writes.ts(examples/userinput/writes.ts)- signing in (OAuth, or an app password), and every change as a record written to your own repository
design.tsx(examples/userinput/design.tsx),markdown.tsx(examples/userinput/markdown.tsx),styles.css(examples/userinput/styles.css)- the design system on React Aria, accessible by keyboard and screen reader; Markdown rendered safely; large type and squircles
home.tsx(examples/userinput/home.tsx),board.tsx(examples/userinput/board.tsx),discussion.tsx(examples/userinput/discussion.tsx),people.tsx(examples/userinput/people.tsx),app.tsx(examples/userinput/app.tsx)- the pages, with the path as the state: routes
matched from the react library's location, and each page's data read once per key withuseData, so going back shows it at once and a refresh after a write keeps it on screen
tcm dev says it all runs in the browser.
reminders: a local-first PWA
Run it (then go offline and reload, or install it)
curl -fsSL https://tcm.codes/docs/examples/reminders.tar.gz | tar xz
reminders/setup.sh /tmp/reminders # builds the codebase there and runs its tests
cd /tmp/reminders && tcm build reminders.App --static site # a static site in site/, for any static host
Reminders in the style of Apple's, kept on the device: there's no server, and nothing leaves it. The docs site
serves it as the plain files tcm build --static writes. It's a PWA: it installs, opens without
a network, and updates itself.
model.ts(examples/reminders/model.ts)- plain functions (which list a reminder is in, due days, a reminder typed in one line) that run anywhere; tests
store.ts(examples/reminders/store.ts)- the device's IndexedDB database, and a channel telling the app's other tabs and windows of a change: browser code, inferred from what it uses
ui.tsx(examples/reminders/ui.tsx)- the app: smart lists and yours, each list a path (
/today,/lists/<id>), so a static build has a page for each smart list; one page at a time on a phone; it says when it's offline, and when a new version is ready (useAppUpdate) pwa.ts(examples/reminders/pwa.ts)- the web app manifest, beside the app; its icons are files of the codebase (
icon.svg(examples/reminders/icon.svg),appicon.png(examples/reminders/appicon.png)) styles.css(examples/reminders/styles.css)- Apple's look, light and dark
playground.ts(examples/reminders/playground.ts)- the scratch file you start with
tcm view reminders.App says it all runs in the browser, which is why tcm build --static can write it as files.
geometry: packages, releases and changelogs
curl -fsSL https://tcm.codes/docs/examples/geometry.tar.gz | tar xz
geometry/setup.sh /tmp/geometry # builds the codebase, and its history, there
code /tmp/geometry # the Releases view, release-geo.md, the playground
One codebase holding two npm packages: geo, a geometry library, and atlas, a command built on it. Each is a
namespace with a manifest (publishing). setup.sh builds up their history step by
step, printing each:
geo.ts(examples/geometry/geo.ts),atlas.ts(examples/geometry/atlas.ts)- two packages in one codebase, one using the other; documented, with tests, and a command (
atlas 0,0 3,4) tcm release geo@1.0.0 --notes …- first releases, declared stable, each with a summary (
notes/(examples/geometry/notes)); tcm writes the rest of the notes steps/geo-1-1.ts(examples/geometry/steps/geo-1-1.ts)- a new definition and an optional parameter: additions, so
tcm release geomakes it 1.1.0 by itself steps/hexagons.ts(examples/geometry/steps/hexagons.ts)- a contribution proposed on a branch, commented on and merged through a shared codebase (
.hub, theoriginremote); a new case ofShapeis breaking, so it's geo 2.0.0, and its notes name the contribution steps/next.ts(examples/geometry/steps/next.ts)- an unreleased change, and a draft of its notes (
release-geo.md) for you to finish and release playground.ts(examples/geometry/playground.ts)- the scratch file: watch expressions over both packages
README.md(examples/geometry/README.md)- the codebase's README, added first: what's in it, and its front page in its forge
Then try:
tcm releases,tcm changelog geo: the releases, and a changelog nobody wrote by hand (releases).tcm release check geo: what geo's next release would be (2.1.0, additions), and the semver findings behind it.tcm pack atlas@1.1.0: an npm package of atlas 1.1, depending ongeo ^1.1.0(the first geo with what it uses) instead of carrying a copy.- In VS Code, the Releases view: both packages, each one's next release with its findings, and their releases.
Click a package for its page and changelog.
release-geo.mdhas a Release lens at the top.setup.shpoints the extension at the tcm that built the codebase (.vscode/settings.json).
effect: a large library
curl -fsSL https://tcm.codes/docs/examples/effect.tar.gz | tar xz
effect/setup.sh /tmp/effect # fetches effect@4.1.2 from npm, imports it (minutes), runs the playground
cd /tmp/effect && tcm view effect.Effect.Effect && tcm run demo.main
Effect, imported whole from its npm package's source: 580 files and 15,671 definitions,
in 6–9 minutes. It's a library written without tcm in mind, and it exercises most of what
importing accepts: interfaces with namespaces of types beside them (Effect.Success<…>),
statements setting up constants (Impl.prototype = Proto), declare global and declare module augmentations,
namespace imports everywhere, and large cycles. Once imported it's code like any other: tcm verify re-renders and
re-hashes every definition in a couple of minutes, and the playground imports it from #codebase/effect/…. Browse
it as a codebase (code).
setup.sh(examples/effect/setup.sh)- the import:
npm pack effect@4.1.2, the changes below, Effect's compiler options,tcm import --into effect changes.patch(examples/effect/changes.patch)- what tcm needs changed, in seven files: four where TypeScript 7.1, which tcm checks with, reports errors 7.0 doesn't; a module object used as a value (
? Aead : Cipher), which tcm can't import yet; and two imports of the package by its own name (effect/Cause), which its npm package maps to its build playground.ts(examples/effect/playground.ts)- programs using Effect: generators, a typed error caught by its tag, an asynchronous sleep; tests
README.md(examples/effect/README.md)- the codebase's README: what's in it, and its front page in its forge
Left out of the import: SchemaJITCompiler/enable.ts, a module there only for its side effect, and the Scalar and
Swagger pages, which load their bundled UIs with import().