Liking cljdoc? Tell your friends :D

com.blockether.vis.ext.channel-tui.cinema

Headless session → MP4 screencast. Replays a persisted session's transcript through the REAL TUI render pipeline (screen/render-frame! painting into a Lanterna VirtualTerminal — no TTY needed), and encodes the captured frames to .mp4:

pure-JVM H.264 via jcodec's SequenceEncoder, fed RGB Pictures whose glyphs are rasterised by com.blockether.imaging (FFM, embedded Noto Sans Mono). Pixel-exact because WE draw the glyphs — no external player font drift, no java.desktop.

The replay is HUMANIZED rather than a flat scroll-through: every disclosure COLLAPSED, the session is re-enacted turn by turn as if it were happening live — a user turn is TYPED IN character by character; before each answer a WORK beat holds the live Vis is calling the provider… spinner in the assistant's place; then the finished answer JUMPS IN and SLOWLY scrolls into view. See session->frames.

The heavy TUI stack (screen, Lanterna) is reached via requiring-resolve so merely loading this namespace stays cheap.

Headless session → MP4 screencast. Replays a persisted session's transcript
through the REAL TUI render pipeline (`screen/render-frame!` painting into a
Lanterna `VirtualTerminal` — no TTY needed), and encodes the captured frames
to `.mp4`:

  pure-JVM H.264 via jcodec's `SequenceEncoder`, fed RGB `Picture`s whose
  glyphs are rasterised by `com.blockether.imaging` (FFM, embedded Noto Sans
  Mono). Pixel-exact because WE draw the glyphs — no external player font
  drift, no `java.desktop`.

The replay is HUMANIZED rather than a flat scroll-through: every disclosure
COLLAPSED, the session is re-enacted turn by turn as if it were happening
live — a user turn is TYPED IN character by character; before each answer a
WORK beat holds the live `Vis is calling the provider…` spinner in the
assistant's place; then the finished answer JUMPS IN and SLOWLY scrolls into
view. See `session->frames`.

The heavy TUI stack (`screen`, Lanterna) is reached via `requiring-resolve`
so merely loading this namespace stays cheap.
raw docstring

cellclj

(cell tc)

One Lanterna TextCharacter as a raster cell — {:ch :fg :bg :bold :italic :underline} holding the colours AND the styles a TERMINAL would really show.

Lanterna's DEFAULT colour means "whatever the host terminal paints", and .getRed reports it as ANSI black — which is why an unpainted cell used to rasterise as a pitch-black void instead of the app's paper. Here it resolves to the theme's own ink/paper. A REVERSE cell is captured already swapped, since nothing downstream carries the modifier.

One Lanterna `TextCharacter` as a raster cell — `{:ch :fg :bg :bold :italic
:underline}` holding the colours AND the styles a TERMINAL would really show.

Lanterna's `DEFAULT` colour means "whatever the host terminal paints", and
`.getRed` reports it as ANSI black — which is why an unpainted cell used to
rasterise as a pitch-black void instead of the app's paper. Here it resolves to
the theme's own ink/paper. A REVERSE cell is captured already swapped, since
nothing downstream carries the modifier.
sourceraw docstring

export!clj

(export! session-id opts)

Render session-id to an MP4 screencast file.

opts: :out output path (default: <session-id>.mp4 in the cwd) :cols :rows :fps :theme :font-size :type-cps :work-ms :jump-hold-ms :scroll-rows-per-frame :post-user-ms :post-assist-ms — see defaults

Returns {:path :format :frames :video-ms :cols :rows}.

Render `session-id` to an MP4 screencast file.

opts:
  :out      output path (default: <session-id>.mp4 in the cwd)
  :cols :rows :fps :theme :font-size
  :type-cps :work-ms :jump-hold-ms :scroll-rows-per-frame :post-user-ms :post-assist-ms  — see `defaults`

Returns `{:path :format :frames :video-ms :cols :rows}`.
sourceraw docstring

frames->mp4!clj

(frames->mp4! {:keys [cols rows frames]}
              out
              {:keys [font-size fps] :or {font-size 18 fps 8}})

Encode a session->frames result to out (an MP4 File/path) with jcodec's pure-Java H.264 SequenceEncoder, fed RGB Pictures rendered by imaging. Returns the output File.

Encode a `session->frames` result to `out` (an MP4 File/path) with jcodec's
pure-Java H.264 `SequenceEncoder`, fed RGB `Picture`s rendered by imaging.
Returns the output File.
sourceraw docstring

grid->png!clj

(grid->png! grid out {:keys [font-size] :or {font-size 18}})

Rasterize ONE captured grid to out as a PNG and return the output File.

The whole "look at the pixels" path: a Lanterna back-buffer becomes an image in process, through the SAME ops the MP4 emitter encodes, in the theme's own colours. Test helper capture/shot! wraps this into a one-call screenshot.

Rasterize ONE captured grid to `out` as a PNG and return the output File.

The whole "look at the pixels" path: a Lanterna back-buffer becomes an image
in process, through the SAME ops the MP4 emitter encodes, in the theme's own
colours. Test helper `capture/shot!` wraps this into a one-call screenshot.
sourceraw docstring

session->framesclj

(session->frames session-id opts)

Replay session-id headless and return {:cols :rows :frames [{:grid :delay-ms} …] :video-ms}.

opts overrides defaults. The replay is HUMANIZED: rather than dumping the whole transcript and scrolling through it, it RE-ENACTS the session as if it were happening live, one message at a time, with every disclosure COLLAPSED (the natural resting view a live session shows, not an expanded dump):

• a USER turn is TYPED IN character by character — the bubble grows as the text lands, like a human at the keyboard — then a short beat; • before each ASSISTANT answer there is a WORK beat: the LIVE progress bubble holds in the assistant's place (⠿ Vis is calling the provider… 1.2s / Esc to cancel, spinner animating, elapsed clock ticking) so it reads as real work being done; • the finished answer then JUMPS IN whole (a bubble popping in near the bottom of the viewport), holds a beat, then SLOWLY scrolls into view; • a beat to read it, and on to the next turn.

Pacing is by FRAME COUNT at a constant fps (the encoder ignores per-frame delays): every 'beat' is that many repeated frames, and the whole clip length scales with the session's content. scroll/follow carries no :pos, so each captured frame SNAPS to its target — deterministic, no stray ease.

Replay `session-id` headless and return
`{:cols :rows :frames [{:grid :delay-ms} …] :video-ms}`.

`opts` overrides `defaults`. The replay is HUMANIZED: rather than dumping the
whole transcript and scrolling through it, it RE-ENACTS the session as if it
were happening live, one message at a time, with every disclosure COLLAPSED
(the natural resting view a live session shows, not an expanded dump):

  • a USER turn is TYPED IN character by character — the bubble grows as the
    text lands, like a human at the keyboard — then a short beat;
  • before each ASSISTANT answer there is a WORK beat: the LIVE progress
    bubble holds in the assistant's place (`⠿ Vis is calling the provider…
    1.2s / Esc to cancel`, spinner animating, elapsed clock ticking) so it
    reads as real work being done;
  • the finished answer then JUMPS IN whole (a bubble popping in near the
    bottom of the viewport), holds a beat, then SLOWLY scrolls into view;
  • a beat to read it, and on to the next turn.

Pacing is by FRAME COUNT at a constant `fps` (the encoder ignores per-frame
delays): every 'beat' is that many repeated frames, and the whole clip
length scales with the session's content. `scroll/follow` carries no `:pos`,
so each captured frame SNAPS to its target — deterministic, no stray ease.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close