Gym Log
개인 맞춤 근력 트레이닝 추적기(PWA)
Sepiola는 웹 텔레스트레이터로 CHIRP 판타지 하키 해설을 화면에 그리고, 분석가가 결정하고 화면은 중립을 유지합니다
Sepiola — a WebMCP telestrator: draws CHIRP's fantasy-hockey reads onto a persistent screen. The analyst decides, the agent draws, the screen has no opinions.
스포츠·피트니스JavaScript · HTMLGitHub @semanticintent온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A WebMCP telestrator: a page that draws an analyst's read onto a persistent screen. The analyst decides. The agent draws. The screen has no opinions.
The first analyst is CHIRP, a fantasy-hockey intelligence MCP server. Its read of your week — who plays, who sits on a back-to-back, who to stream, games in hand — used to arrive as a paragraph in a chat window. Here it arrives as a rink.README 전문 보기 ↗A WebMCP telestrator: a page that draws an analyst's read onto a persistent screen. The analyst decides. The agent draws. The screen has no opinions.
The first analyst is CHIRP, a fantasy-hockey intelligence MCP server. Its read of your week — who plays, who sits on a back-to-back, who to stream, games in hand — used to arrive as a paragraph in a chat window. Here it arrives as a rink.
Live: https://sepiola.semanticintent.dev
Why the name. Sepiola is the bobtail squid. A cuttlefish's skin is a display of millions of pigment cells driven directly by its brain: a neuron fires and a pixel shows, the neuron stops and the skin clears. The skin decides nothing. And the passing cloud, a dark band that travels across the body to hold prey still, is a spotlight done by an animal. That is this page: a skin for an analyst's brain, with a circle move nature got to first.
read_ice 7 2026-10-12 in the Talkback before opening night).https://chirp-mcp.semanticintent.dev/mcp:claude mcp add --transport http chirp https://chirp-mcp.semanticintent.dev/mcp
It works on a phone too, as a single column. Add ?analyst=fixtures to run without the analyst.
Television spent sixty years learning how to show reasoning: circle the defender, run it back, split screen. That vocabulary is what this page exposes as tools. Three roles, kept apart:
| Role | Who | Does | Never |
|---|---|---|---|
| Analyst | CHIRP, over HTTP | Computes, decides, explains; returns a structured read | Draws, holds screen state |
| Pen | Any WebMCP agent, or a human in the console | Turns the viewer's question into moves; adds the take | Reads the graphic aloud |
| Screen | This page | Draws, remembers, lets the viewer touch | Forms an opinion |
The invariant that makes it work: every number and every sentence on screen comes from the analyst's read or from the interface copy. A test enforces it. If the screen ever ranks, sums, compares, or composes a sentence, something has leaked.
The pattern is called the telestrator and is written up in docs/pattern.md. Sepiola is its first worked example.
| Move | Tool | On screen |
|---|---|---|
| Load the board | cue_roster(text | fixture) | Resolve a lineup onto the rink |
| Read the ice | read_ice(look_ahead_days?, start?) | Fetch the read; reveal ice quality, badges, the panel, games in hand |
| Circle him | circle(ids, reason?) | Spotlight one skater with the reason pinned above; stays until wiped |
| Run it back | replay(id) | His week as tiles, his line, his projected points, the analyst's verdict |
| Split screen | split(a, b) | Two skaters' weeks side by side; the analyst's call on who starts |
| Cut to | cut_to(view) | Bring a window forward: rink, panel, hand, replay, console |
| Put up the board | cue_board(drafted_text?, mine_text?, categories?) | The draft board: tiers by position, drafted players crossed off by the analyst; with your picks, the analyst's next pick marked on it; with your league's categories, ranked for them |
| Wipe | wipe() | Clean the screen; the roster stays cued |
Every move returns a structured acknowledgment of what it drew. The table is generated from src/grammar.js into docs/grammar.md and a test fails if it drifts. Producer moves (ready, roll, caption, layer) are designed and deliberately not built until a second analyst exists.
The page registers the eight moves with navigator.modelContext (falling back to document.modelContext) using the W3C Community Group draft's descriptor shape — name, title, description, inputSchema, annotations, execute. Registration is derived from the grammar, so a tool exists in exactly one place. execute returns the same acknowledgment the console shows. Every agent call lands in the talkback transcript, so the viewer sees what the pen did.
Hosts today: Chrome 146+ behind the enable-webmcp-testing flag, and the Codex / ChatGPT desktop app's embedded browser. The menubar pill says whether tools registered.
// what a pen does, in the browser
const tool = (n) => navigator.modelContext.tools.find((t) => t.name === n);
await tool('cue_roster').execute({ text: pastedLineup });
await tool('read_ice').execute({ look_ahead_days: 7 });
await tool('circle').execute({ ids: ['8478397'], reason: '4 games, back-to-back' });
contracts/read.schema.json is what the analyst returns and the only thing the screen may draw. Per skater: id, name, jersey number, position, slot, club, one game bit per day, back-to-back, a schedule value 0–100, a flag, a one-line reason, points per game, projected points. Per read: the start / sit / stream / IR calls, games in hand for you and the opponent, the closing line for every replay, the take, and the sources. Optional notes carry what the analyst could not resolve, so nothing vanishes silently.
The contract lives here because the screen defines what it can draw; the analyst adapts. CHIRP vendors a copy and byte-diffs it in its tests. Two fixtures in fixtures/ are instances of it; the page validates every live read against the schema before a handler sees it.
Any analyst that returns this shape gets this screen.
Everything that has meaning is data. Only rendering is code.
| Meaning | Lives in |
|---|---|
| What the analyst can say | contracts/read.schema.json |
| What the pen can do | src/grammar.js — one array; handlers are pure (state, input) → state |
| What is on screen right now | src/state.js — one object; nothing hidden in the DOM |
| How things move | src/motion/sequences/*.json — timed steps over a small verb vocabulary, run by src/motion/runner.js (GSAP) |
Views are pure (state) → markup and re-render only what a move touched. The transcript is state too. Vanilla ES modules, SVG, GSAP, Vite; no framework, because Sepiola already has a grammar and a framework would be a second one to hold. Fonts are inlined; the whole page is one 250 kB file.
Verification a model can run without eyes:
npm test # contract (Ajv), views idempotent, no-opinions (every text node ∈ read ∪ copy), console, grammar doc, WebMCP descriptors
npm run scenarios # scenarios/*.txt played through Playwright, screenshots to test/shots/, a fake modelContext, a mocked analyst
ARCHITECTURE.md has the full picture; docs/decisions.md has every choice and why.
npm install
npm run dev # http://localhost:5173 — fixture mode; add ?analyst=<url> for a live analyst
npm test
npm run scenarios
npm run build # dist/sepiola.html (one file) + dist/index.html for Pages
npm run deploy # Cloudflare Pages
Production builds default to the hosted analyst, chirp-edge, a Cloudflare Worker face of CHIRP. The same host is also a stateless MCP server at https://chirp-mcp.semanticintent.dev/mcp, so an agent can reach the analyst's 23 tools directly and this page's 7 moves through WebMCP: two faces, one analyst, no proxying (D38). Override with ANALYST_URL=... npm run build. To run the analyst yourself: in the CHIRP repo, npm run build && npm run serve:http gives you POST /read on localhost:3200.
contracts/read.schema.json the contract
fixtures/ reads the screen can run without an analyst
scenarios/ one move per line; console and tests both speak them
src/grammar.js the eight moves
src/state.js the whole show
src/views/ rink spot strips chrome panel hand replay console
src/motion/ runner.js + sequences/*.json
src/analyst.js the only line to the analyst (fixtures or POST /read)
src/contract.js validates a live read against the schema file
src/webmcp.js registration derived from the grammar
src/talkback.js console convenience: a surname stands in for an id
docs/ overview, pattern, decisions, plan, grammar (generated)
reference/telestrator-v0.html the original mockup; the visual target, never edited
Built and live: the screen at sepiola.semanticintent.dev, the analyst at chirp-mcp.semanticintent.dev, CHIRP read_ice on npm (4.3.0). Jerseys carry all 32 clubs' colours. Open: the producer layer when a second analyst arrives. See docs/plan.md.
The story of building it is an essay on semanticintent.dev: The Screen That Has No Opinions. The pattern is written up as a short paper, docs/paper/telestrator-pattern.md: context, forces, the pattern, this worked example, and six things building it taught. Cite the software with CITATION.cff (GitHub shows a "Cite this repository" button). Archived on Zenodo: concept DOI 10.5281/zenodo.22387039 for all versions, 10.5281/zenodo.22387040 for 0.1.0.
MIT. Barlow and Barlow Condensed are by Jeremy Tribby under the SIL Open Font License 1.1 (src/fonts/OFL.txt). No team logos, wordmarks, or jersey designs: generic shapes in club colours only.