Skip to content

Tom draws back — the oracle can answer with a sketch#17

Closed
vnnkl wants to merge 2 commits into
MaximeRivest:mainfrom
vnnkl:feat/tom-draws-back
Closed

Tom draws back — the oracle can answer with a sketch#17
vnnkl wants to merge 2 commits into
MaximeRivest:mainfrom
vnnkl:feat/tom-draws-back

Conversation

@vnnkl

@vnnkl vnnkl commented Jul 7, 2026

Copy link
Copy Markdown

Ask in ink — "draw me a little house with a tree" — and the reply is a drawing: pen strokes inking themselves onto the page in Tom's hand, placed among whatever words come with them. Draw a noughts-and-crosses grid and make a move: the writer's ink fades when the diary drinks it, so Tom redraws the whole board with his move added.

How

  • Protocol: the persona now always carries a drawing protocol. The model may emit one ⟦draw:x,y x,y; …⟧ block — quill strokes on a 100×100 canvas — anywhere in its reply; where the block sits among the words is where the sketch sits on the page.
  • Parser: StreamParser gained a span-aware body scanner. Prose still streams sentence-by-sentence; a complete draw block flushes the prose before it and becomes Event::Draw; unterminated tails are dropped; unparseable blocks are ignored (never inked, never an error); a stray mid-prose ⟦show⟧ is swallowed exactly as before. Leading ⟦show:N⟧ routing is unchanged.
  • Placement (draw.rs, new): the sketch's canvas bbox is scaled uniformly (capped at 900px / page margins / remaining room below the prose), centered, and every segment is subdivided into ~2.5px steps displaced by a slow sine wobble (dying at the model's own vertices) so lines read as drawn by a hand, not plotted. Deterministic per sketch.
  • Animation: a placed sketch is just more WritePlan strokes — the existing reply animator inks it, and streamed prose continues beneath it.
  • Diagnostics: --oracle-test prints [sketch: N strokes, M points] plus the raw strokes, for judging how well a model draws before pointing the diary at it.

Tested end-to-end against gpt-5.5: "draw me a little house with a tree beside it" produced a coherent 8-stroke house (door, window, gabled roof) and tree (trunk, lumpy crown, two branches) on the first try, alongside the prose "Of course."

16 new unit tests (7 parser, 9 draw); the full suite passes. The prompt gates drawing on the writer asking (or a game demanding it), so ordinary diary turns are unaffected.

The persona now carries a drawing protocol: when the writer asks for a
drawing, a map, or a move in a drawn game, the model may emit one
⟦draw:x,y x,y; …⟧ block of quill strokes on a 100×100 canvas, placed
among its words. The stream parser routes complete blocks as
Event::Draw (prose before a block is flushed, unterminated tails are
dropped, bad blocks are ignored); draw.rs scales the sketch onto the
page, centers it below the prose written so far, and subdivides every
segment into pen-sized steps with a slow sine wobble so the lines read
as drawn by a hand, not plotted. The reply animator inks it like any
other streamed chunk, and prose may continue beneath.

--oracle-test prints the raw strokes of any sketch, for judging how
well a model draws before pointing the diary at it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9adecefd5d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread riddle/src/oracle.rs
return out; // directive still streaming in
}
out.push(Err("unfinished conjuring directive".into()));
out.push(Err("unfinished directive".into()));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle truncated leading draw blocks without an error

When a reply starts with a draw block and the model or stream ends before the closing , this error path runs before the body scanner can apply the new “drop unterminated draw tails” behavior. In that truncated-sketch scenario, e.g. a drawing cut off by RIDDLE_OPENAI_MAX_TOKENS or a stalled stream, the diary reports an oracle failure and skips transcript handling, whereas non-leading unfinished draw blocks are silently dropped as intended.

Useful? React with 👍 / 👎.

A drawn game exposed two amnesias. First, only prose was kept in the
reply record — the ⟦draw:…⟧ block was consumed by the parser and never
stored, so the next turn's history had no trace of the board Tom drew:
every move looked like move one, and he took the centre again and
again. The serialized block now rides in the reply record, and the
protocol tells him to repeat his last block's strokes exactly and add
only the new marks, so the board never shifts between turns.

Conjuring learned to cope: stored blocks are stripped from the spoken
text (raw coordinates are never inked) and the sketches they describe
are redrawn on the remembered page in faded ink, after the words.
@vnnkl

vnnkl commented Jul 7, 2026

Copy link
Copy Markdown
Author

Follow-up after a real game of noughts and crosses on the device: the first playtest exposed two amnesias — the ⟦draw⟧ block wasn't kept in the reply record (so every turn looked like move one and Tom took the centre repeatedly), and the writer's X reached the oracle as a lone X on white paper (the snapshot replays only the writer's strokes, so the board wasn't in it).

This branch now keeps the serialized block in the reply record and tells Tom to repeat his last block's coordinates exactly when continuing a game; conjuring strips the raw block from spoken text and redraws the sketch in faded ink instead. The visual half (replaying the sketch beneath the writer's ink in the oracle snapshot) builds on the stroke-model to_png from #15, so it lives as a separate commit on top of both — happy to attach it here if #15 lands first.

Verified with a board-plus-centre-X snapshot against gpt-5.5: "A bold opening. I shall take a corner." and a redraw with the grid unchanged, the X still in the centre cell, and an O in the top-left corner.

@vnnkl vnnkl closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant