luv

Workshop wiki

terminal-wall.lisp

luvcraft/terminal-wall.lisp

system luvcraft/core · 141 definitions · on GitHub

A Ghostty terminal projected across a rectangle of authored world blocks.

in-package#:luvcraft
defclassterminal-grid-domain
columns:initarg:columns:readerterminal-grid-domain-columns
rows:initarg:rows:readerterminal-grid-domain-rows
defmethoddomains:domain-cardinality
*
terminal-grid-domain-columnsdomain
terminal-grid-domain-rowsdomain
defunterminal-grid-offset
domaincolumnrow

Return the row-major offset for column,row in domain.

let
columns
terminal-grid-domain-columnsdomain
rows
terminal-grid-domain-rowsdomain
unless
and
<=0column
<columncolumns
<=0row
<rowrows
error"Terminal cell (~D,~D) is outside ~Dx~D."columnrowcolumnsrows
+column
*rowcolumns
defunterminal-grid-coordinate
domainoffset

Return COLUMN and ROW for row-major offset in domain.

unless
error"Terminal offset ~D is outside a ~D-cell grid."offset
multiple-value-bind
rowcolumn
flooroffset
terminal-grid-domain-columnsdomain
valuescolumnrow
defstruct
terminal-grid-presentation
:constructor%make-terminal-grid-presentation
&keydomaincharactersscreen
domaincharacters

The styled Ghostty snapshot behind CHARACTERS, or NIL for plain text.

screen
defstructterminal-glyph-occurrenceglyphcolumnrow

Packed #xRRGGBB foreground and whether the bold face was used.

foregroundbold-p
defparameter*luvcraft-fonts-directory*
asdf:system-relative-pathname"luvcraft/core""fonts/"
"The checkout's bundled fonts, captured while the system is loaded."
defparameter*terminal-display-font-pathname*
luvcraft-font-pathname"MonaspaceNeon-Regular.ttf"
defparameter*terminal-display-default-foreground*#xF4EFE1"Packed sRGB #xRRGGBB used for cells without an explicit foreground."

A terminal cell's colour arrives as a display colour: the byte a shell would have written to a monitor, whose white means "as bright as this screen goes". The scene it is drawn into measures radiance instead, and a lit tube in a daylit room is emphatically brighter than its own diffuse surroundings. These gains are that conversion, and they are also what carries lit glyphs over the presentation bloom threshold, so the glow around bright text is the ordinary lens chain seeing an ordinary bright thing rather than a halo painted onto the terminal.

defparameter*terminal-ink-emission*2.3"Radiance per unit of glyph ink, in scene units where diffuse white is one."
defparameter*terminal-background-emission*1.15"Radiance per unit of cell-background colour, held below the ink's own."
defparameter*terminal-font-scale*1.0

The multiplier on the font size that fits a display's grid to its face; the default a new display takes.

The frame records screen-right, screen-up, and outward in voxel axes. EQL methods keep the six closed orientations inspectable without making block materials or terminal surfaces branch on their names.

defstruct
terminal-face-frame
:constructormake-terminal-face-frame
rightupoutward
rightupoutward
defgenericterminal-face-frame
face
defclassterminal-surface
world:initarg:world:readerterminal-surface-world
material:initarg:material:readerterminal-surface-material
absent-neighbor-policy:initarg:absent-neighbor-policy:initform:air:readerterminal-surface-absent-neighbor-policy
face:initarg:face:readerterminal-surface-face

The block at screen-space column zero, row zero (lower left).

origin:initarg:origin:readerterminal-surface-origin
block-width:initarg:block-width:readerterminal-surface-width
block-height:initarg:block-height:readerterminal-surface-height

These keys are the exact authored chunk materializations whose block content can change membership or exposure. Owner keys are the subset whose visible native meshes carry the display face itself.

dependency-keys:initformnil:accessorterminal-surface-dependency-keys
owner-chunk-keys:initformnil:accessorterminal-surface-owner-chunk-keys
dependency-stamp:initformnil:accessorterminal-surface-retained-dependency-stamp
observed-world-revision:initform-1:accessorterminal-surface-observed-world-revision
state:initform:current:accessorterminal-surface-state
reconciliations:initform0:accessorterminal-surface-reconciliations

A terminal display draws onto *some* rectangle. The wall's rectangle is a run of blocks (terminal-surface); a phone's is a small plane in the hand. Everything downstream -- glyph placement, cell backgrounds, the screen panel and faceplate -- asks the surface only these questions.

defgenericterminal-surface-axes
surface
:documentation

Return surface's unit RIGHT, UP, and OUTWARD vectors as three vec3s, in the coordinate space the surface's display is drawn in.

defgenericterminal-surface-lower-left-point
surface&optionaloffset
:documentation

Return the point offset cell-depths outside surface's lower left corner, as seen from its outward side.

defgenericterminal-surface-physical-width
surface
:documentation

surface's width along its right axis, in cells.

defgenericterminal-surface-physical-height
surface
:documentation

surface's height along its up axis, in cells.

defgenericterminal-surface-current-p
surface&optionalsession
:documentation

True when surface's last coherently published derived state is current.

defgenericterminal-surface-focus-score
surfacesession
:documentation

A non-negative score when the display on surface can be entered by TAB, or NIL. Lower is nearer.

defgenericterminal-surface-focus-camera-pose
surfacesession
:documentation

The camera pose from which surface's display is best read, or NIL to leave the camera where it is with only the narrowed field of view.

defgenericterminal-surface-panel-frame
surfacesession&optionaloffset
:documentation

Where a panel mounted flat on surface sits in the world this frame.

Returns the panel's centre point, its half-width vector along the surface's right, its half-height vector pointing *down* the texture, and the outward unit normal -- all in world space, offset cell-depths off the face. A wall's answer never changes; a surface carried in the hand answers afresh each frame, which is why this takes the session and is asked at draw time rather than once at mounting.

:method
surfacesession&optional
offset0.010
declare
ignoresession

The general surface draws in world space already, so its own axes and corner are the answer.

multiple-value-bind
rightupoutward
defmethodterminal-surface-axes
let
frame
terminal-face-frame
terminal-surface-facesurface
values
voxel-direction-vec3
terminal-face-frame-rightframe
voxel-direction-vec3
terminal-face-frame-upframe
voxel-direction-vec3
terminal-face-frame-outwardframe
defmethodterminal-surface-focus-camera-pose
destructuring-bind
canvas-extent
luvcraft-session-contextsession
multiple-value-call
lambda
lefttoprightbottom
terminal-focus-camera-posesurfacewidthheightlefttoprightbottom
defmethodterminal-surface-focus-score
multiple-value-bind
hitstatus
declare
ignorestatus
whenhit
let
coordinate
block-ray-hit-coordinatehit
when
loopforrowbelow
terminal-surface-heightsurface
thereis
loopforcolumnbelow
terminal-surface-widthsurface
thereis
equalpcoordinate
block-ray-hit-distancehit
defclassterminal-display
session:initarg:session:initformnil:readerterminal-display-session
surface:initarg:surface:readerterminal-display-surface
mode:initform:shell:accessorterminal-display-mode

LUVCRAFT/MCCLIM presentations install their browser here. The terminal remains the focus owner and delegates drawing and events to this child only while its mode calls for it.

mode-overlay:initformnil:accessorterminal-display-mode-overlay
film-screen:initformnil:accessorterminal-display-film-screen

The wall's name, which its shell learns as luvcraft_PARENT_SCREEN, and the portal showing a child luvcraft that asked for that name.

name:initarg:name:initform:readerterminal-display-name
portal:initformnil:accessorterminal-display-portal
terminal:initarg:terminal:initformnil:readerterminal-display-terminal
device:initarg:device:initformnil:accessorterminal-display-device
presentation:initarg:presentation:initformnil:accessorterminal-display-presentation
glyph-cache:initarg:glyph-cache:initformnil:readerterminal-display-glyph-cache

Keyed by (CHARACTER . BOLD-P).

glyphs-by-character:initform
make-hash-table:test#'equal
:readerterminal-display-glyphs-by-character
glyph-run:initarg:glyph-run:initformnil:accessorterminal-display-glyph-run
font-pathname:initarg:font-pathname:initformnil:readerterminal-display-font-pathname
bold-font-pathname:initarg:bold-font-pathname:initformnil:readerterminal-display-bold-font-pathname
default-foreground:initarg:default-foreground:initform*terminal-display-default-foreground*:readerterminal-display-default-foreground
cell-run:initarg:cell-run:initformnil:accessorterminal-display-cell-run
screen-run:initarg:screen-run:initformnil:accessorterminal-display-screen-run
faceplate-run:initarg:faceplate-run:initformnil:accessorterminal-display-faceplate-run
margin:initarg:margin:initform0.12:readerterminal-display-margin
font-scale:initarg:font-scale:initform*terminal-font-scale*:accessorterminal-display-font-scale
dirty-p:initformnil:accessorterminal-display-dirty-p
refresh-count:initform0:accessorterminal-display-refresh-count
frame-bind-groups:initform
make-hash-table:test#'eq
:readerterminal-display-frame-bind-groups
defgenericchange-terminal-display-mode
displaysessionmode
:documentation

Select display's focused wall mode.

The built-in modes are the EQL-specialized symbols :SHELL and :FILM. LUVCRAFT/MCCLIM adds an :AFTER method which supplies the film browser, while the display continues to own focus and movie lifetime.

defmethodchange-terminal-display-mode
mode
eql:shell
setf
terminal-display-modedisplay
mode
display

A child luvcraft on the wall. The shell on this wall carries the portal server's socket in its environment; a luvcraft started there connects and asks for this wall by name, and its picture takes the wall over until it goes away (Ctrl-C in the shell still reaches the shell, so that is how).

defunopen-terminal-display-portal
displaymirror

Put the ready child mirror on display's wall and switch it to :PORTAL mode.

let
session
terminal-display-sessiondisplay
surface
terminal-display-surfacedisplay
unlesssession
error"Terminal display ~S is not attached to a session."display
let
portal
open-luvcraft-portalsession:mirrormirror:attach-pnil:rectangle
lambda
aspect
:on-stop
lambda
portal
declare
ignoreportal
setf
terminal-display-portaldisplay
portal
terminal-display-modedisplay
:portal
portal
defunterminal-portal-panel
displayaspect

The portal panel for display: the whole face, and inside it the picture of aspect fitted with the same margin the text grid keeps, so the wall's proportions hold when a shell becomes a portal. Returns the panel's origin, right edge, and up edge, then the picture rectangle in panel UV.

let*
surface
terminal-display-surfacedisplay
margin
terminal-display-margindisplay
available-width
-surface-width
*2margin
available-height
-surface-height
*2margin
available-aspect
/available-widthavailable-height
width
if
>aspectavailable-aspect
available-width
*available-heightaspect
height
if
>aspectavailable-aspect
/available-widthaspect
available-height
left
/
-surface-widthwidth
2.0
bottom
/
-surface-heightheight
2.0
multiple-value-bind
originright-edgeup-edge
terminal-film-rectanglesurface
/surface-widthsurface-height
valuesoriginright-edgeup-edge

Panel V runs down the picture (the quad flips it), so the bottom margin is the top of the rectangle in UV.

list
/leftsurface-width
/bottomsurface-height
/
+leftwidth
surface-width
/
+bottomheight
surface-height
defunclose-terminal-display-portal
display

Take the child off display's wall, if one is there, and go back to the shell.

alexandria:when-let
portal
terminal-display-portaldisplay
session
terminal-display-sessiondisplay
setf
terminal-display-portaldisplay
nil
when
eq:portal
terminal-display-modedisplay
setf
terminal-display-modedisplay
:shell
setf
terminal-display-dirty-pdisplay
t
display
defmethodchange-terminal-display-mode
mode
eql:film

Selecting Film again while a movie is running returns to its browser.

setf
terminal-display-modedisplay
mode
display
defunterminal-display-delegate-overlay
display

display's mode child, when the mode is one that presents through it.

:SHELL drives a PTY and owns its own drawing and keys. Every other mode installs a presentation overlay and works through it -- except while a film is actually playing, when the wall is a screen and not a control.

unless
or
eq:shell
terminal-display-modedisplay
terminal-display-film-screendisplay
terminal-display-mode-overlaydisplay
defunsplit-terminal-lines
text
loopwithstart=0forend=
position#\Newlinetext:startstart
collect
string-right-trim'
#\Return
subseqtextstartend
whileenddo
setfstart
1+end
defunmake-terminal-grid-presentation
domaintext

Copy formatted terminal text into one exact dense viewport domain.

let*
columns
terminal-grid-domain-columnsdomain
rows
terminal-grid-domain-rowsdomain
characters
make-array:element-type'character:initial-element#\Space
loopforlineinforrowbelowrowsdo
loopforcharacteracrosslineforcolumnbelowcolumnsdo
setf
arefcharacters
terminal-grid-offsetdomaincolumnrow
character
%make-terminal-grid-presentation:domaindomain:characterscharacters
defunmake-terminal-screen-presentation
domainscreen

Copy a styled Ghostty screen snapshot into one exact viewport domain.

let*
columns
terminal-grid-domain-columnsdomain
rows
terminal-grid-domain-rowsdomain
characters
make-array:element-type'character:initial-element#\Space
dotimes
row
minrows
ghostty:terminal-screen-rowsscreen
dotimes
column
mincolumns
ghostty:terminal-screen-columnsscreen
setf
arefcharacters
terminal-grid-offsetdomaincolumnrow
%make-terminal-grid-presentation:domaindomain:characterscharacters:screenscreen
defunterminal-presentation-cell-style
presentationcolumnrow

Return foreground #xRRGGBB, background #xRRGGBB or NIL, and bold-p.

let
screen
terminal-grid-presentation-screenpresentation
if
andscreen
<column
ghostty:terminal-screen-columnsscreen
<row
ghostty:terminal-screen-rowsscreen
multiple-value-bind
foregroundbackground
valuesforegroundbackground
defunterminal-grid-character
presentationcolumnrow
aref
terminal-grid-presentation-characterspresentation
terminal-grid-offset
terminal-grid-presentation-domainpresentation
columnrow
defunterminal-fixture-framed-line
content
formatnil"│ ~76A │"content
defunterminal-display-fixture

Return deterministic fake PTY output for the world display proof.

let
escape
code-char27
return
code-char13
with-output-to-string
stream
formatstream"~C[2J~C[H"escapeescape
dolist
line
list"┌──────────────────────────────────────────────────────────────────────────────┐"
terminal-fixture-framed-line"luvcraft :: ghostty terminal block material"
"├──────────────────────────────────────────────────────────────────────────────┤"
terminal-fixture-framed-line"one 80 x 24 terminal projected across one linked 8 x 5 block surface"
terminal-fixture-framed-line"Darwin little-world arm64 26.0.0"
terminal-fixture-framed-line"$ ./scripts/wiki marks next"
terminal-fixture-framed-line"NTQ5KY Bridge Ghostty render-state rows into the world display"
terminal-fixture-framed-line"Ghostty owns the grid. Luv owns the voxels. Slug owns the curves."
terminal-fixture-framed-line" ├─ material :terminal"
terminal-fixture-framed-line" ├─ face :back"
terminal-fixture-framed-line" ├─ blocks 8 x 5"
terminal-fixture-framed-line" └─ cells 80 x 24"
terminal-fixture-framed-line"the font grid belongs to the whole face rectangle, not to each block"
terminal-fixture-framed-line"$ echo 'hello from the magic voxel tv'"
terminal-fixture-framed-line"hello from the magic voxel tv"
"└──────────────────────────────────────────────────────────────────────────────┘"
write-stringlinestream
write-charreturnstream
terpristream
defunterminal-offset-point
origin&restvector-scales
let
x
vec3-xorigin
y
vec3-yorigin
z
vec3-zorigin
loopfor
vectorscale
onvector-scalesby#'cddrdo
incfx
*
vec3-xvector
scale
incfy
*
vec3-yvector
scale
incfz
*
vec3-zvector
scale
defunvoxel-direction-vec3
direction
make-vec3
voxel-direction-dxdirection
voxel-direction-dydirection
voxel-direction-dzdirection
defunterminal-coordinate-step
coordinatedirection&optional
amount1
make-world-coordinate
+
world-coordinate-xcoordinate
*amount
voxel-direction-dxdirection
+
world-coordinate-ycoordinate
*amount
voxel-direction-dydirection
+
world-coordinate-zcoordinate
*amount
voxel-direction-dzdirection
defunterminal-absent-neighbor-solid-p
policycoordinate
ecasepolicy
:airnil
:solidt
:error
error"Terminal surface reached absent terrain at ~S."coordinate
defunterminal-face-exposed-p
worldmaterialcoordinateoutwardabsent-neighbor-policy
multiple-value-bind
blockavailability
sample-block-atworld
world-coordinate-xcoordinate
world-coordinate-ycoordinate
world-coordinate-zcoordinate
and
eqavailability:resident
eqblockmaterial
let
neighbor
terminal-coordinate-stepcoordinateoutward
multiple-value-bind
outsideoutside-availability
sample-block-atworld
world-coordinate-xneighbor
world-coordinate-yneighbor
world-coordinate-zneighbor
ecaseoutside-availability
:resident
:absent
not
terminal-absent-neighbor-solid-pabsent-neighbor-policyneighbor

Discovery is a discover-once frontier program (#K3PCP3): starting from one exposed terminal face, admit coplanar neighbours which are the same material and exposed, mark each once, and retain the admitted component. The compiled realization walks chunk offsets through the world's chunk window; no coordinate objects, hash keys, or conses appear per site.

frontiers:define-frontier-programterminal-surface-discovery:family:discover-once:frontier-layout:lifo-stack:neighborhood
:voxel-relationscoplanar-directions
:fields
visited:memot
terminalexposed
:constants
materialoutwardabsent-neighbor-policycoplanar-directionsmemo
:admission
and
terminaltarget
exposedtarget
:retain-admissionst
defunterminal-discovery-visited-lane
memochunk

The per-chunk visited bits owned by one discovery's memo table.

or
gethashchunkmemo
setf
gethashchunkmemo
make-array
chunk-domain-cardinality
block-chunk-domainchunk
:element-type'bit:initial-element0
defunterminal-site-exposed-p
windowchunkoffsetoutwardpolicy

Whether the outward neighbour of CHUNK/OFFSET leaves that face visible.

let
domain
block-chunk-domainchunk
multiple-value-bind
local-xlocal-ylocal-z
multiple-value-bind
world-xworld-yworld-z
chunk-domain-world-componentsdomainlocal-xlocal-ylocal-z
multiple-value-bind
neighborneighbor-offsetavailability
locate-chunk-window-sitewindow
+world-x
voxel-direction-dxoutward
+world-y
voxel-direction-dyoutward
+world-z
voxel-direction-dzoutward
ecaseavailability
:available
not
block-solid-p
block-content-at-offset
block-chunk-contentneighbor
neighbor-offset
:unavailable
ecasepolicy
:airt
:solidnil
:error
error"Terminal surface reached absent terrain at ~S."
make-world-coordinate
+world-x
voxel-direction-dxoutward
+world-y
voxel-direction-dyoutward
+world-z
voxel-direction-dzoutward
defunterminal-discovery-bindings
list
frontiers:make-frontier-field-binding'visited:lanes'
bits:typesimple-bit-vector
:read'
=1
sbitbitsoffset
:write'
setf
sbitbitsoffset
1
frontiers:make-frontier-field-binding'terminal:lanes'
content
block-chunk-contentmaterialization
:read'
eqmaterial

Exposure probes the outward neighbour through the window; it is only worth asking once the site is terminal material, so it reads lazily.

frontiers:make-frontier-field-binding'exposed:read'
terminal-site-exposed-pwindowmaterializationoffsetoutwardabsent-neighbor-policy
:lazyt
defundiscover-terminal-component
worldxyzfacematerialabsent-neighbor-policy

Discover the coplanar exposed component of material containing X,Y,Z.

Return the retained execution, or NIL and a status when the seed itself is not an exposed terminal face.

let*
right
terminal-face-frame-rightframe
up
terminal-face-frame-upframe
outward
terminal-face-frame-outwardframe
frontier
frontiers:make-realization-frontierrealization:initial-capacity64
execution
frontiers:make-realization-executionrealizationworldfrontier
memo
make-hash-table:test#'eq
multiple-value-bind
chunkoffsetavailability
unless
and
eqavailability:available
eq
block-content-at-offset
block-chunk-contentchunk
offset
material
return-fromdiscover-terminal-component
valuesnil:not-terminal
unless
terminal-site-exposed-pworldchunkoffsetoutwardabsent-neighbor-policy
return-fromdiscover-terminal-component
valuesnil:covered
flet
constants
list:materialmaterial:outwardoutward:absent-neighbor-policyabsent-neighbor-policy:coplanar-directionsdirections:memomemo
apply#'frontiers:admit-frontier-realization-siterealizationworldfrontierexecutionchunkoffsetnil
constants
apply#'frontiers:drain-frontier-realizationrealizationworldfrontierexecution
constants
valuesexecution:component
defunmap-execution-admitted-sites
functionexecution

Call function with the world X, Y, Z of every retained admitted site.

let*
sites
frontiers:frontier-execution-admitted-sitesexecution
chunks
frontiers:frontier-site-buffer-materialization-lanesites
offsets
frontiers:frontier-site-buffer-offset-lanesites
dotimes
index
frontiers:frontier-site-buffer-lengthsites
let*
chunk
arefchunksindex
domain
block-chunk-domainchunk
multiple-value-bind
local-xlocal-ylocal-z
chunk-domain-local-componentsdomain
arefoffsetsindex
multiple-value-bind
xyz
chunk-domain-world-componentsdomainlocal-xlocal-ylocal-z
funcallfunctionxyz
defunfind-terminal-surface
worldxyzface&key
material*terminal-block*
absent-neighbor-policy:air

Discover the maximal exposed rectangular terminal surface at X,Y,Z,face.

Return the surface and :RECTANGLE. A seed which is not terminal, is covered, or belongs to a non-rectangular coplanar component instead returns NIL and a descriptive status. Discovery runs the compiled terminal-surface-discovery program; this function only folds the retained component into a rectangle.

let*
right
terminal-face-frame-rightframe
up
terminal-face-frame-upframe
multiple-value-bind
executionstatus
discover-terminal-componentworldxyzfacematerialabsent-neighbor-policy
unlessexecution
return-fromfind-terminal-surface
valuesnilstatus
let
minimum-umost-positive-fixnum
maximum-umost-negative-fixnum
minimum-vmost-positive-fixnum
maximum-vmost-negative-fixnum
count0
origin-x0
origin-y0
origin-z0
flet
projection
xyzdirection
+
*x
voxel-direction-dxdirection
*y
voxel-direction-dydirection
*z
voxel-direction-dzdirection
map-execution-admitted-sites
lambda
xyz
let
u
projectionxyzright
v
projectionxyzup
incfcount
setfminimum-u
minminimum-uu
maximum-u
maxmaximum-uu
minimum-v
minminimum-vv
maximum-v
maxmaximum-vv
execution
map-execution-admitted-sites
lambda
xyz
when
and
=minimum-u
projectionxyzright
=minimum-v
projectionxyzup
setforigin-xxorigin-yyorigin-zz
execution
let
width
1+
-maximum-uminimum-u
height
1+
-maximum-vminimum-v
unless
return-fromfind-terminal-surface
valuesnil:non-rectangular
let
surface
make-instance'terminal-surface:worldworld:materialmaterial:absent-neighbor-policyabsent-neighbor-policy:faceface:origin
make-world-coordinateorigin-xorigin-yorigin-z
:block-widthwidth:block-heightheight
valuessurface:rectangle
defunterminal-surface-coordinate
surfacecolumnrow
let*
frame
terminal-face-frame
terminal-surface-facesurface
across
terminal-coordinate-step
terminal-surface-originsurface
terminal-face-frame-rightframe
column
terminal-coordinate-stepacross
terminal-face-frame-upframe
row
defunterminal-surface-shape-current-p
surface

Check surface membership and maximality against authored world content.

let*
world
terminal-surface-worldsurface
material
terminal-surface-materialsurface
absent-neighbor-policy
terminal-surface-absent-neighbor-policysurface
frame
terminal-face-frame
terminal-surface-facesurface
right
terminal-face-frame-rightframe
up
terminal-face-frame-upframe
outward
terminal-face-frame-outwardframe
width
terminal-surface-widthsurface
height
terminal-surface-heightsurface
and
loopforrowbelowheightalways
loopforcolumnbelowwidthalways
terminal-face-exposed-pworldmaterialoutwardabsent-neighbor-policy

A newly adjacent exposed terminal block means this retained rectangle is no longer maximal; its renderer must be rediscovered/rebuilt.

loopforrowbelowheightalways
and
not
terminal-face-exposed-pworldmaterialoutwardabsent-neighbor-policy
not
terminal-face-exposed-pworldmaterialoutwardabsent-neighbor-policy
loopforcolumnbelowwidthalways
and
not
terminal-face-exposed-pworldmaterialoutwardabsent-neighbor-policy
not
terminal-face-exposed-pworldmaterialoutwardabsent-neighbor-policy
defunterminal-surface-dependency-coordinates
surface

Return the cold set of cells whose content determines surface validity.

let*
frame
terminal-face-frame
terminal-surface-facesurface
right
terminal-face-frame-rightframe
up
terminal-face-frame-upframe
outward
terminal-face-frame-outwardframe
width
terminal-surface-widthsurface
height
terminal-surface-heightsurface
coordinatesnil
labels
observe
coordinate
pushcoordinatecoordinates
push
terminal-coordinate-stepcoordinateoutward
coordinates
coordinates
defunterminal-coordinate-chunk-key
spacecoordinate
multiple-value-bind
chunk-xchunk-ychunk-z
voxel-space-decompose-componentsspace
world-coordinate-xcoordinate
world-coordinate-ycoordinate
world-coordinate-zcoordinate
chunk-keychunk-xchunk-ychunk-z
defunterminal-sort-chunk-keys
keys
sort
remove-duplicateskeys:test#'equal
lambda
leftright
loopforainleftforbinrightwhen
/=ab
return
<ab
finally
defunterminal-surface-dependency-stamp
surface

Name the authored chunk materializations which justify surface.

let
world
terminal-surface-worldsurface
loopforkeyin
terminal-surface-dependency-keyssurface
collect
multiple-value-bind
chunkpresent-p
apply#'world-chunk-atworldkey
ifpresent-p
list
copy-listkey
block-chunk-incarnationchunk
block-chunk-revisionchunk
list
copy-listkey
nil
defuninitialize-terminal-surface-dependencies
surface
let*
world
terminal-surface-worldsurface
space
block-world-spaceworld
owner-keys
loopforrowbelow
terminal-surface-heightsurface
append
loopforcolumnbelow
terminal-surface-widthsurface
collect
dependency-keys
setf
terminal-surface-owner-chunk-keyssurface
terminal-surface-dependency-keyssurface
terminal-surface-retained-dependency-stampsurface
terminal-surface-observed-world-revisionsurface
block-world-revisionworld
terminal-surface-statesurface
:current
surface
defunterminal-surface-visible-mesh-current-p
surfacesession

Whether each native mesh carrying surface is a current visible product.

let
products
luvcraft-session-chunk-productssession
loopforkeyin
terminal-surface-owner-chunk-keyssurface
forproduct=
gethashkeyproducts
always
andproduct
defunreconcile-terminal-surface
surface&optionalsession

Reconcile derived surface state after its native mesh publication boundary.

An authored edit does not immediately alter the retained display. When the surface's visible chunk products are still stale, the old geometry and glyph projection remain one last-known-good cohort.

let*
world
terminal-surface-worldsurface
world-revision
block-world-revisionworld
unless
=world-revision
terminal-surface-observed-world-revisionsurface
let
cond
equalstamp
terminal-surface-retained-dependency-stampsurface

The edit was outside the chunks this surface observes.

setf
terminal-surface-observed-world-revisionsurface
world-revision

Keep both halves of the old visible cohort until native mesh publication catches up. Revisit on the next frame.

nil
t
setf
terminal-surface-retained-dependency-stampsurface
stamp
terminal-surface-observed-world-revisionsurface
world-revision
terminal-surface-statesurface
if:current:invalid
incf
terminal-surface-reconciliationssurface
terminal-surface-statesurface
defmethodterminal-surface-current-p
&optionalsession
eq:current
defunterminal-surface-axis-extent
surfacedirection
let
extent
voxel-space-cell-extent
block-world-space
terminal-surface-worldsurface
+
*
abs
voxel-direction-dxdirection
vec3-xextent
*
abs
voxel-direction-dydirection
vec3-yextent
*
abs
voxel-direction-dzdirection
vec3-zextent
defmethodterminal-surface-physical-width
let
frame
terminal-face-frame
terminal-surface-facesurface
*
terminal-surface-widthsurface
terminal-surface-axis-extentsurface
terminal-face-frame-rightframe
defmethodterminal-surface-physical-height
let
frame
terminal-face-frame
terminal-surface-facesurface
*
terminal-surface-heightsurface
terminal-surface-axis-extentsurface
terminal-face-frame-upframe
defunterminal-film-rectangle
surfacefilm-aspect

Fit film-aspect inside surface and return its lower-left and edge vectors.

let*
frame
terminal-face-frame
terminal-surface-facesurface
right
voxel-direction-vec3
terminal-face-frame-rightframe
up
voxel-direction-vec3
terminal-face-frame-upframe
surface-aspect
/surface-widthsurface-height
width
if
>film-aspectsurface-aspect
surface-width
*surface-heightfilm-aspect
height
if
>film-aspectsurface-aspect
/surface-widthfilm-aspect
surface-height
left-margin
/
-surface-widthwidth
2.0
bottom-margin
/
-surface-heightheight
2.0
origin
terminal-offset-pointrightleft-marginupbottom-margin
defunstop-terminal-display-film
displaysession

Stop and release display's owned movie, if any.

alexandria:when-let
screen
terminal-display-film-screendisplay
when
when
eqscreen
luvcraft-session-video-screensession
setf
luvcraft-session-video-screensession
nil
setf
terminal-display-film-screendisplay
nil
display
defunplay-terminal-display-film
displaypathname&key
hardware:required

Play pathname on display's authored wall using the session's video backend.

hardware is the decode policy make-video-screen takes. It defaults to :REQUIRED, which is right for authored films whose codec is known, and wrong for a film that arrived from somewhere: whatever a stranger's phone recorded is not necessarily something this device can decode in hardware, and :AUTO lets it fall back to software rather than refusing to play.

let*
session
terminal-display-sessiondisplay
surface
terminal-display-surfacedisplay
unlesssession
error"Terminal display ~S is not attached to a session."display
let
screen
make-video-screen
luvcraft-session-devicesession
luvcraft-session-camerasession
pathname+luvcraft-scene-color-format+:hardwarehardware:rectangle
lambda
aspect
setf
terminal-display-film-screendisplay
screen
luvcraft-session-video-screensession
screen
terminal-display-modedisplay
:film
screen
defmethodterminal-surface-lower-left-point
&optional
offset0.006

Return the metric world point offset cell-depths outside the lower left.

let*
origin
terminal-surface-originsurface
space
block-world-space
terminal-surface-worldsurface
cell-origin
extent
voxel-space-cell-extentspace
frame
terminal-face-frame
terminal-surface-facesurface
right
terminal-face-frame-rightframe
up
terminal-face-frame-upframe
outward
terminal-face-frame-outwardframe
labels
component
point-readerdirection-reader
let
base
funcallpoint-readercell-origin
cell-size
funcallpoint-readerextent
normal
funcalldirection-readeroutward
horizontal
funcalldirection-readerright
vertical
funcalldirection-readerup
+base
*cell-size
+
cond
pluspnormal
1.0
minuspnormal
0.0
minusphorizontal
1.0
minuspvertical
1.0
t0.0
*normaloffset
make-vec3
component#'vec3-x#'voxel-direction-dx
component#'vec3-y#'voxel-direction-dy
component#'vec3-z#'voxel-direction-dz
defunplace-terminal-block-rectangle
worldorigin-xorigin-yorigin-zfacewidthheight&key
material*terminal-block*

Place a width by height terminal-material rectangle in resident world.

ORIGIN is the lower-left block as seen from face's outward side.

check-typewidth
integer1
check-typeheight
integer1
let*
origin
make-world-coordinateorigin-xorigin-yorigin-z
with-world-change-transaction
world
dotimes
dotimes
columnwidth
let
coordinate
terminal-coordinate-step
terminal-coordinate-steporigin
terminal-face-frame-rightframe
column
terminal-face-frame-upframe
row
edit-block-atmaterialworld
world-coordinate-xcoordinate
world-coordinate-ycoordinate
world-coordinate-zcoordinate
world
defunfit-terminal-grid-in-surface
domainsurfacefont-advancefont-heightmarginfont-scale

Fit domain uniformly inside surface and return scale, left, bottom, width, and height in world units. font-scale is an explicit multiplier on contain.

check-typemargin
real0
check-typefont-scale
real
0
let*
available-width
-surface-width
*2margin
available-height
-surface-height
*2margin
columns
terminal-grid-domain-columnsdomain
rows
terminal-grid-domain-rowsdomain
unless
and
pluspavailable-width
pluspavailable-height
error"Margin ~S leaves no room on a ~,3Fx~,3F terminal surface."marginsurface-widthsurface-height
let*
scale
*font-scale
min
/available-width
*columnsfont-advance
/available-height
*rowsfont-height
grid-width
*columnsfont-advancescale
grid-height
*rowsfont-heightscale
valuesscale
/
-surface-widthgrid-width
2.0
/
-surface-heightgrid-height
2.0
grid-widthgrid-height
defstruct
terminal-face
:constructormake-terminal-face
pathnameloader

One font file and its open loader.

pathnameloader
defunterminal-display-character-glyphs
characterbold-pglyphs-by-characterglyph-cacheface
let
key
conscharacterbold-p
multiple-value-bind
cached-glyphspresent-p
gethashkeyglyphs-by-character
ifpresent-pcached-glyphs
setf
gethashkeyglyphs-by-character
luv.slug:make-slug-glyph-placements
luv.slug:cached-slug-shaped-textglyph-cache
terminal-face-pathnameface
stringcharacter
terminal-face-loaderface
glyph-cache
terminal-face-pathnameface
defunterminal-display-glyph-occurrences
presentationglyphs-by-characterglyph-cacheregularbold
let
occurrencesnil
domain
terminal-grid-presentation-domainpresentation
dotimes
row
terminal-grid-domain-rowsdomain
dotimes
column
terminal-grid-domain-columnsdomain
let
character
terminal-grid-characterpresentationcolumnrow
unless
char=character#\Space
multiple-value-bind
foregroundbackgroundbold-p
declare
ignorebackground
dolist
glyph
terminal-display-character-glyphscharacterbold-pglyphs-by-characterglyph-cache
ifbold-pboldregular
push
make-terminal-glyph-occurrence:glyphglyph:columncolumn:rowrow:foregroundforeground:bold-pbold-p
occurrences
nreverseoccurrences
defunsrgb-byte-to-linear
byte
let
value
/byte255.0
if
<=value0.04045
/value12.92
expt
/
+value0.055
1.055
2.4
defunpacked-color-linear-components
packed

Return linear R G B floats for one packed sRGB #xRRGGBB.

defunscaled-color-linear-components
packedemission

Return one packed sRGB display colour as emission units of scene radiance.

multiple-value-bind
redgreenblue
values
*redemission
*greenemission
*blueemission
defunterminal-font-metrics
font-loader

Return the em-normalized line height, advance, and descender.

let*
ascender
zpb-ttf:ascenderfont-loader
descender
zpb-ttf:descenderfont-loader
units-per-em
zpb-ttf:units/emfont-loader
values
/
-ascenderdescender
units-per-em
/
zpb-ttf:advance-width
zpb-ttf:find-glyph#\Mfont-loader
units-per-em
/descenderunits-per-em
defunmake-terminal-display-glyph-instances
occurrencesatlasdomainsurfacefont-loadermarginfont-scale

Place glyphs in one font grid fitted across the entire block surface.

multiple-value-bind
font-heightfont-advancedescender-ratio
multiple-value-bind
rightup
let*

The vertex stage dilates each quad by pixels; this is only the static em padding, normally zero.

data
make-array
*24
lengthoccurrences
:element-type'single-float
multiple-value-bind
scaleleftbottomgrid-widthgrid-height
fit-terminal-grid-in-surfacedomainsurfacefont-advancefont-heightmarginfont-scale
declare
ignoregrid-width
labels
difference
endstart
make-vec3
-
vec3-xend
vec3-xstart
-
vec3-yend
vec3-ystart
-
vec3-zend
vec3-zstart
write-values
offsetvalues
loopforvalueinvaluesforindexfromoffsetdo
setf
arefdataindex
coercevalue'single-float
loopforoccurrenceinoccurrencesforbasefrom0by24forglyph=
terminal-glyph-occurrence-glyphoccurrence
forcolumn=
terminal-glyph-occurrence-columnoccurrence
forrow=
terminal-glyph-occurrence-rowoccurrence
forbaseline=
+bottomgrid-height
-
*
1+row
font-heightscale
*
-descender-ratio
scale
forcell-x=
+left
*columnfont-advancescale
foroutline-left=
-
luv.slug:slug-glyph-placement-outline-min-xglyph
padding
foroutline-bottom=
-
luv.slug:slug-glyph-placement-outline-min-yglyph
padding
foroutline-right=
+
luv.slug:slug-glyph-placement-outline-max-xglyph
padding
foroutline-top=
+
luv.slug:slug-glyph-placement-outline-max-yglyph
padding
forglyph-origin=
terminal-offset-pointoriginright
+cell-x
*
luv.slug:slug-glyph-placement-origin-xglyph
scale
up
+baseline
*
luv.slug:slug-glyph-placement-origin-yglyph
scale
forquad-origin=
terminal-offset-pointglyph-originright
*outline-leftscale
up
*outline-bottomscale
forright-edge=
terminal-offset-pointglyph-originright
*outline-rightscale
up
*outline-bottomscale
fortop-edge=
terminal-offset-pointglyph-originright
*outline-leftscale
up
*outline-topscale
forresource=
luv.slug:slug-glyph-placement-resourceglyph
forserialized=
luv.slug:slug-device-glyph-serializedresource
foratlas-location=
gethashresource
luv.slug:slug-glyph-atlas-locationsatlas
do
multiple-value-bind
redgreenblue
scaled-color-linear-components
terminal-glyph-occurrence-foregroundoccurrence
*terminal-ink-emission*

The three spare Z lanes carry the linear ink colour.

write-valuesbase
list
vec3-xquad-origin
vec3-yquad-origin
vec3-zquad-origin
vec3-x
differenceright-edgequad-origin
vec3-y
differenceright-edgequad-origin
vec3-z
differenceright-edgequad-origin
vec3-x
differencetop-edgequad-origin
vec3-y
differencetop-edgequad-origin
vec3-z
differencetop-edgequad-origin
outline-leftoutline-bottom
luv.slug:slug-serialized-outline-horizontal-band-countserialized
outline-rightoutline-top
luv.slug:slug-serialized-outline-vertical-band-countserialized
firstatlas-location
secondatlas-location
red
luv.slug:slug-glyph-placement-outline-min-xglyph
luv.slug:slug-glyph-placement-outline-min-yglyph
green
luv.slug:slug-glyph-placement-outline-max-xglyph
luv.slug:slug-glyph-placement-outline-max-yglyph
blue
data
defunmake-terminal-display-cell-instances
presentationsurfacefont-loadermarginfont-scale

Build one background record per same-coloured run of cells in a row.

Each record is origin, right edge, up edge, and linear rgb: 12 floats. The edges span the exact painted rectangle; the shader pads the quad itself and resolves the analytic edge, so adjacent runs meet without seams.

multiple-value-bind
font-heightfont-advance
multiple-value-bind
rightup
let*
domain
terminal-grid-presentation-domainpresentation

Sit just below the glyph plane so ink always wins the depth test.

valuesnil
count0
multiple-value-bind
scaleleftbottomgrid-widthgrid-height
fit-terminal-grid-in-surfacedomainsurfacefont-advancefont-heightmarginfont-scale
declare
ignoregrid-width
let
cell-width
*font-advancescale
cell-height
*font-heightscale
flet
emit
rowstartendbackground
let
corner
terminal-offset-pointoriginright
+left
*startcell-width
up
+bottomgrid-height
-
*
1+row
cell-height
width
*
-endstart
cell-width
multiple-value-bind
redgreenblue
incfcount
push
list
vec3-xcorner
vec3-ycorner
vec3-zcorner
*
vec3-xright
width
*
vec3-yright
width
*
vec3-zright
width
*
vec3-xup
cell-height
*
vec3-yup
cell-height
*
vec3-zup
cell-height
redgreenblue
values
dotimes
row
terminal-grid-domain-rowsdomain
let
run-startnil
run-colornil
dotimes
column
terminal-grid-domain-columnsdomain
multiple-value-bind
foregroundbackground
declare
ignoreforeground
unless
eqlbackgroundrun-color
whenrun-color
emitrowrun-startcolumnrun-color
setfrun-startcolumnrun-colorbackground
whenrun-color
emitrowrun-start
terminal-grid-domain-columnsdomain
run-color
let
data
make-array
*12count
:element-type'single-float
index0
dolist
record
nreversevalues
dolist
valuerecord
setf
arefdataindex
coercevalue'single-float
incfindex
data
defunmake-terminal-display-screen-instances
surface&optional
offset0.003

Build the one screen-panel record spanning the whole display surface.

The record shares the cell run's layout: origin, right edge, up edge, then the outward face normal in the lane the cell run uses for ink. offset names which of the terminal's coplanar rectangles this is: the default sits just below the cell backgrounds, so both they and the glyphs win the depth test against it while it hides the block tiles behind the screen, and the faceplate's larger offset sits in front of the glyphs instead.

multiple-value-bind
rightupoutward
let*
data
make-array12:element-type'single-float
values
list
vec3-xorigin
vec3-yorigin
vec3-zorigin
*
vec3-xright
width
*
vec3-yright
width
*
vec3-zright
width
*
vec3-xup
height
*
vec3-yup
height
*
vec3-zup
height
vec3-xoutward
vec3-youtward
vec3-zoutward
loopforvalueinvaluesforindexfrom0do
setf
arefdataindex
coercevalue'single-float
data
defunmake-terminal-display-glyph-population
presentationsurfaceglyph-cacheglyphs-by-characterfont-pathnamebold-font-pathnamemarginfont-scale

Return glyphs, atlas, glyph instances, and background cell instances.

zpb-ttf:with-font-loader
font-loaderfont-pathname
zpb-ttf:with-font-loader
bold-loader
orbold-font-pathnamefont-pathname
let
regular
make-terminal-facefont-pathnamefont-loader
bold
make-terminal-face
orbold-font-pathnamefont-pathname
bold-loader

Keep ordinary shell interaction on one stable atlas. Unicode output grows this retained character set only when a genuinely new character first appears, rather than manufacturing an atlas for every screen.

loopforcodefrom32to126do
terminal-display-character-glyphs
code-charcode
nilglyphs-by-characterglyph-cacheregular
terminal-display-character-glyphs
code-charcode
tglyphs-by-characterglyph-cachebold
let*
occurrences
terminal-display-glyph-occurrencespresentationglyphs-by-characterglyph-cacheregularbold
glyphs
mapcar#'terminal-glyph-occurrence-glyphoccurrences
atlas-keys
sort
loopforkeybeingthehash-keysofglyphs-by-charactercollectkey
lambda
ab
or
<
char-code
cara
char-code
carb
and
char=
cara
carb
not
cdra
cdrb
atlas-glyphs
loopforkeyinatlas-keysappend
copy-list
gethashkeyglyphs-by-character
atlas
luv.slug:slug-glyph-atlas-forglyph-cacheatlas-glyphs
instances
make-terminal-display-glyph-instancesoccurrencesatlas
terminal-grid-presentation-domainpresentation
surfacefont-loadermarginfont-scale
cell-instances
make-terminal-display-cell-instancespresentationsurfacefont-loadermarginfont-scale
valuesglyphsatlasinstancescell-instances
defclassterminal-cell-run
pipeline:initarg:pipeline:readerterminal-cell-run-pipeline
vertex-buffer:initarg:vertex-buffer:readerterminal-cell-run-vertex-buffer
instance-buffer:initarg:instance-buffer:accessorterminal-cell-run-instance-buffer
count:initarg:count:initform0:accessorterminal-cell-run-count
:documentation

Solid background quads behind terminal cells, sharing the glyph run's frame bind group so both draw against the same camera uniform.

defunmake-terminal-cell-run
sessionglyph-runinstances&key
role:terminal-cell
vertex-rolerole
label"terminal cell backgrounds"

Build an analytic world-rectangle run of role over 48-byte instances.

The default role draws cell backgrounds; :terminal-screen draws the one screen panel from make-terminal-display-screen-instances with the same vertex layout, and :TERMINAL-FACEPLATE draws the glass over the finished picture from that same rectangle, which is why vertex-role is separable: two materials can share one placement stage without sharing a name.

let*
device
luvcraft-session-devicesession
vertex-buffernil
instance-buffernil
pipelinenil
completed-pnil
unwind-protect
progn
setfvertex-buffer
createdevice
make-buffer-descriptor:label"terminal cell quads":size
*4
lengthvertex-data
:usage'
:vertex:copy-dst
instance-buffer
createdevice
make-buffer-descriptor:label"terminal cell instances":size
max4
*4
lengthinstances
:usage'
:vertex:copy-dst
pipeline
make-live-shader-pipeline:rolerole:vertex-rolevertex-role:labellabel:devicedevice:layout
world-text-run-layoutglyph-run
:vertex-buffers'
:array-stride12:attributes
:shader-location0:offset0:format:float32x3
:array-stride48:step-mode:instance:attributes
:shader-location1:offset0:format:float32x3
:shader-location2:offset12:format:float32x3
:shader-location3:offset24:format:float32x3
:shader-location4:offset36:format:float32x3
:target-format+luvcraft-scene-color-format+:target-blend:premultiplied-alpha:primitive'
:topology:triangle-list
:depth-stencil'
:format:depth32-float:depth-write-enablednil:depth-compare:less
write-buffervertex-buffervertex-data
when
plusp
lengthinstances
write-bufferinstance-bufferinstances
setfcompleted-pt
make-instance'terminal-cell-run:pipelinepipeline:vertex-buffervertex-buffer:instance-bufferinstance-buffer:count
floor
lengthinstances
12
unlesscompleted-p
whenpipeline
ignore-errors
wheninstance-buffer
ignore-errors
destroyinstance-buffer
whenvertex-buffer
ignore-errors
destroyvertex-buffer
defunreplace-terminal-cell-run-instances
rundeviceinstances
let
buffer
createdevice
make-buffer-descriptor:label"terminal cell instances":size
max4
*4
lengthinstances
:usage'
:vertex:copy-dst
when
plusp
lengthinstances
write-bufferbufferinstances
let
old
terminal-cell-run-instance-bufferrun
setf
terminal-cell-run-instance-bufferrun
buffer
terminal-cell-run-countrun
floor
lengthinstances
12
run
defunrelease-terminal-cell-run
release-live-shader-pipeline
terminal-cell-run-pipelinerun
destroy
terminal-cell-run-instance-bufferrun
destroy
terminal-cell-run-vertex-bufferrun
values
defunmake-terminal-display-glyph-run
sessionpresentationsurfaceglyph-cacheglyphs-by-characterfont-pathnamebold-font-pathnamemarginfont-scale

Return the glyph run and its companion background cell run.

multiple-value-bind
glyphsatlasinstancescell-instances
make-terminal-display-glyph-populationpresentationsurfaceglyph-cacheglyphs-by-characterfont-pathnamebold-font-pathnamemarginfont-scale
let*
let
glyph-run
make-world-text-run-from-instances
luvcraft-session-devicesession
+luvcraft-scene-color-format+"terminal display"font-pathnamenilglyphsatlascenter1.0instances:label"terminal surface Slug glyphs"
valuesglyph-run
make-terminal-cell-runsessionglyph-runcell-instances
defunclear-terminal-display-frame-bind-groups
display
maphash
lambda
framegroup
declare
ignoreframe
destroygroup
terminal-display-frame-bind-groupsdisplay
clrhash
terminal-display-frame-bind-groupsdisplay
display
defmethodluvcraft-overlay-live-shader-pipelines
list*
world-text-run-pipeline
terminal-display-glyph-rundisplay
append
loopforrunin
list
terminal-display-cell-rundisplay
terminal-display-screen-rundisplay
terminal-display-faceplate-rundisplay
whenruncollect
terminal-cell-run-pipelinerun
alexandria:when-let
portal
terminal-display-portaldisplay
zdefmethod
refresh-luvcraft-overlay:zone:terminal/refresh
alexandria:when-let

The wall's shaders are as live as the block world's: a redefined :terminal-screen or :terminal-cell method rebuilds here, at the frame boundary, keeping the last good pipeline on failure.

when
terminal-display-dirty-pdisplay

Clearing before the snapshot preserves an output notification which races after this point; that later notification requests another frame publication instead of being lost.

setf
terminal-display-dirty-pdisplay
nil
let
completed-pnil
unwind-protect
let*
device
terminal-display-devicedisplay
old-presentation
terminal-display-presentationdisplay
presentation
progn

Unstyled cells take the wall's own ink colour.

setf
ghostty:terminal-screen-default-foregroundscreen
terminal-display-default-foregrounddisplay
make-terminal-screen-presentation
terminal-grid-presentation-domainold-presentation
screen
multiple-value-bind
glyphsatlasinstancescell-instances
make-terminal-display-glyph-populationpresentation
terminal-display-surfacedisplay
terminal-display-glyph-cachedisplay
terminal-display-glyphs-by-characterdisplay
terminal-display-font-pathnamedisplay
terminal-display-bold-font-pathnamedisplay
terminal-display-margindisplay
terminal-display-font-scaledisplay
multiple-value-bind
runatlas-changed-p
replace-world-text-run-instances
terminal-display-glyph-rundisplay
luvcraft-session-devicesession
textglyphsatlasinstances
declare
ignorerun
when
terminal-display-cell-rundisplay
replace-terminal-cell-run-instances
terminal-display-cell-rundisplay
luvcraft-session-devicesession
cell-instances
setf
terminal-display-presentationdisplay
presentation
incf
terminal-display-refresh-countdisplay
setfcompleted-pt
unlesscompleted-p
setf
terminal-display-dirty-pdisplay
t
display
defgenericterminal-display-frame-uniform-buffer
displayframe
:documentation

The frame uniform buffer display's runs draw against in frame.

A wall draws in world coordinates against the session's own frame uniform. A display whose surface lives in some other space -- a phone in the hand -- supplies a uniform whose camera is expressed in that space instead.

defmethodterminal-display-frame-uniform-buffer
luvcraft-frame-uniform-bufferframe
defunterminal-display-frame-bind-group
displayframe
or
gethashframe
terminal-display-frame-bind-groupsdisplay
let
group
aref
make-world-text-frame-bind-groups
terminal-display-glyph-rundisplay
luvcraft-session-device
terminal-display-sessiondisplay
0
setf
gethashframe
terminal-display-frame-bind-groupsdisplay
group
group
zdefmethod
encode-luvcraft-overlay:zone:terminal/encode
sessionpasssurface-texture
when
terminal-surface-current-p
terminal-display-surfacedisplay
session
let
frame
luvcraft-frame-statesessionsurface-texture
faceplate-run
terminal-display-faceplate-rundisplay
case
terminal-display-modedisplay
:shell
let
glyph-run
terminal-display-glyph-rundisplay
cell-run
terminal-display-cell-rundisplay
screen-run
terminal-display-screen-rundisplay
when
andscreen-run
plusp
terminal-cell-run-countscreen-run
set-pipelinepass
live-shader-pipeline-native-pipeline
terminal-cell-run-pipelinescreen-run
set-vertex-bufferpass0
terminal-cell-run-vertex-bufferscreen-run
set-vertex-bufferpass1
terminal-cell-run-instance-bufferscreen-run
drawpass6
terminal-cell-run-countscreen-run
when
andcell-run
plusp
terminal-cell-run-countcell-run
set-pipelinepass
live-shader-pipeline-native-pipeline
terminal-cell-run-pipelinecell-run
set-vertex-bufferpass0
terminal-cell-run-vertex-buffercell-run
set-vertex-bufferpass1
terminal-cell-run-instance-buffercell-run
drawpass6
terminal-cell-run-countcell-run
when
andglyph-run
plusp
length
world-text-run-glyphsglyph-run
set-vertex-bufferpass0
world-text-run-vertex-bufferglyph-run
set-vertex-bufferpass1
world-text-run-instance-bufferglyph-run
drawpass6
length
world-text-run-glyphsglyph-run
:portal

A child game's picture, under this wall's glass like the text.

alexandria:when-let
portal
terminal-display-portaldisplay
encode-luvcraft-portal-pictureportalsessionpasssurface-texture
t

Film, Telegram, and other presentation-layer modes all draw through the mode's own overlay.

alexandria:when-let
encode-luvcraft-overlayoverlaysessionpasssurface-texture

The glass goes on last over shell, browser, or movie: raster, corners, and reflections belong in front of the finished picture.

when
andfaceplate-run
plusp
terminal-cell-run-countfaceplate-run
set-pipelinepass
live-shader-pipeline-native-pipeline
terminal-cell-run-pipelinefaceplate-run
set-vertex-bufferpass0
terminal-cell-run-vertex-bufferfaceplate-run
set-vertex-bufferpass1
terminal-cell-run-instance-bufferfaceplate-run
drawpass6
terminal-cell-run-countfaceplate-run
display
defmethodrelease-luvcraft-overlay
alexandria:when-let
session
terminal-display-sessiondisplay
#+darwin (unregister-luvcraft-portal-screen session (terminal-display-name display))
alexandria:when-let
overlay
terminal-display-mode-overlaydisplay
setf
terminal-display-mode-overlaydisplay
nil
when
terminal-display-devicedisplay
termdev:close-pty-device
terminal-display-devicedisplay
setf
terminal-display-devicedisplay
nil
when
terminal-display-faceplate-rundisplay
release-terminal-cell-run
terminal-display-faceplate-rundisplay
setf
terminal-display-faceplate-rundisplay
nil
when
terminal-display-screen-rundisplay
release-terminal-cell-run
terminal-display-screen-rundisplay
setf
terminal-display-screen-rundisplay
nil
when
terminal-display-cell-rundisplay
release-terminal-cell-run
terminal-display-cell-rundisplay
setf
terminal-display-cell-rundisplay
nil
release-world-text-run
terminal-display-glyph-rundisplay
luv.slug:release-slug-glyph-cache
terminal-display-glyph-cachedisplay
ghostty:close-terminal
terminal-display-terminaldisplay
display
defmethodevict-luvcraft-overlay-frame-key
frame-key

Presentation modes are child overlays rather than independent session attachments, so propagate capture-target eviction through this owner.

alexandria:when-let
overlay
terminal-display-mode-overlaydisplay
display
defmethodhandle-luvcraft-focus-event

Keys still reach the shell under a portal: that is how the child gets its Ctrl-C.

if
member
terminal-display-modedisplay
'
:shell:portal
let
device
terminal-display-devicedisplay
t
let
ifoverlayt
defmethodluvcraft-focus-score
session
terminal-surface-focus-score
terminal-display-surfacedisplay
session

A screen framed exactly square-on stops being a thing in the world and becomes a pasted screenshot: nothing in the picture reports that the terminal has a plane, a bezel with depth, or a room around it. A few degrees of azimuth and elevation give the frame back its perspective and let the faceplate's reflections and rim curvature actually appear, while staying far short of the angle at which a glyph's stem starts to matter.

defparameter*terminal-focus-azimuth*9.0"Degrees the focused view stands to the side of the screen's own normal."
defparameter*terminal-focus-elevation*4.5"Degrees the focused view stands above the screen's own centre."

--------------------------------------------------------------------- The terminal's knobs.

The emissions and the font scale are baked into each display's glyph instances, so a display must repopulate to show a change: that is the terminal-realization, and the knobs carrying it are TERMINAL-KNOBs.

defunterminal-displays
session

Every terminal display among session's overlays.

remove-if-not
lambda
overlay
typepoverlay'terminal-display
luvcraft-session-overlayssession
defunmark-terminal-displays-dirty
session

Ask every terminal display in session to rebuild its glyphs next frame.

dolist
display
setf
terminal-display-dirty-pdisplay
t
session
defclassterminal-realization
:documentation

The value is baked into terminal glyph instances; every terminal display must repopulate.

defunterminal-font-scale
session

The font scale session's displays use: the first display's, or the default a new one would take.

let
display
first
ifdisplay
terminal-display-font-scaledisplay
*terminal-font-scale*
defun
scalesession
dolist
display
setf
terminal-display-font-scaledisplay
scale
scale
define-knobterminal-ink-emission
:label"terminal ink":group:terminal:class'terminal-knob:quantity
:quantity:emission-gain:unit:one
:unit-label"×":minimum0.2:maximum6.0:step0.1
*terminal-ink-emission*
define-knobterminal-background-emission
:label"terminal background":group:terminal:class'terminal-knob:quantity
:quantity:emission-gain:unit:one
:unit-label"×":minimum0.0:maximum3.0:step0.05
*terminal-background-emission*
define-knobterminal-font-scale
:label"terminal font":group:terminal:class'terminal-knob:quantity
:quantity:font-scale:unit:one
:unit-label"×":minimum0.3:maximum2.0:step0.05
define-knobterminal-focus-azimuth
:label"focus azimuth":group:terminal:quantity
:quantity:angle:unit:degree
:minimum-30.0:maximum30.0:step0.5
*terminal-focus-azimuth*
define-knobterminal-focus-elevation
:label"focus elevation":group:terminal:quantity
:quantity:angle:unit:degree
:minimum-20.0:maximum20.0:step0.5
*terminal-focus-elevation*
defunterminal-focus-eye-direction
rightupoutwardazimuthelevation

The unit direction from a screen's centre toward a viewer standing at azimuth and elevation degrees off that screen's outward normal.

let*
radian
coerce
/pi180.0
'single-float
rise
*elevationradian
defunterminal-focus-camera-pose
surfaceviewport-widthviewport-height&optional
left-inset0.0
top-inset0.0
right-inset0.0
bottom-inset0.0

Return a camera pose which contains surface inside the safe view.

Framing is solved rather than approximated. For an eye at distance D from the surface centre along EYE-DIRECTION, a corner at offset O from that centre lands at dot(O, camera-right) * focal / (aspect * (D - dot(O, EYE-DIRECTION))) across and at the matching quotient down, because the camera's own right and up axes are perpendicular to its forward axis and so drop out of the depth. Inverting that for each capacity gives the smallest D at which one corner is just inside the safe view; the pose takes the largest of the four. With the focus angles at zero this is exactly the head-on width-and-height solution it generalizes.

let*
width
coerceviewport-width'single-float
height
coerceviewport-height'single-float
margin
left-capacity
-1.0
/
*2.0
+left-insetmargin
width
right-capacity
-1.0
/
*2.0
+right-insetmargin
width
top-capacity
-1.0
/
*2.0
+top-insetmargin
height
bottom-capacity
-1.0
/
*2.0
+bottom-insetmargin
height
horizontal-capacity
minleft-capacityright-capacity
vertical-capacity
+top-capacitybottom-capacity
unless
and
plusphorizontal-capacity
pluspvertical-capacity
error"Focus insets leave no safe viewport inside ~Dx~D."viewport-widthviewport-height
let*
frame
terminal-face-frame
terminal-surface-facesurface
right
voxel-direction-vec3
terminal-face-frame-rightframe
up
voxel-direction-vec3
terminal-face-frame-upframe
outward
voxel-direction-vec3
terminal-face-frame-outwardframe
center
terminal-offset-pointlower-leftrighthalf-widthuphalf-height
focal
forward
vec3-scaleeye-direction-1.0
pitch
asin
max-1.0
min1.0
vec3-yforward
yaw
if
>
abs
cospitch
1e-5
atan
vec3-xforward
vec3-zforward
atan
-
vec3-zright
vec3-xright

The camera carries no roll, so its own basis follows from the pose it is about to be given rather than from the surface.

camera-right
camera-up
make-vec3
-
*
sinpitch
sinyaw
cospitch
-
*
sinpitch
cosyaw

Move the eye down the surface just enough to place the terminal in the center of the unobscured view rather than the full frame.

vertical-shift
*half-height
/
-top-capacitybottom-capacity
vertical-capacity
upward-capacity
maxtop-capacity1e-3
downward-capacity
maxbottom-capacity1e-3
distance
max1.5
loopforcolumnin
list
-half-width
half-width
maximize
loopforrowin
list
-half-height
half-height
maximize
let*
offset
terminal-offset-point
make-vec30.00.00.0
rightcolumnuprow
across
abs
vec3-dotoffsetcamera-right
raised
+
vec3-dotoffsetcamera-up
vertical-shift
across-need
/
*acrossfocal
*aspecthorizontal-capacity
raised-need
if
pluspraised
/
*raisedfocal
upward-capacity
/
*
-raised
focal
downward-capacity
+
vec3-dotoffseteye-direction
maxacross-needraised-need
position
terminal-offset-pointcentereye-directiondistancecamera-up
-vertical-shift
make-camera-posepositionyawpitchfield-of-view
defunblock-ray-hit-face
hit

Return the exposed block face through which hit entered its block.

let
coordinate
block-ray-hit-coordinatehit
adjacent
block-ray-hit-adjacent-coordinatehit
whenadjacent
find-if
lambda
face
let
neighbor
block-face-neighborface
and
=
+
world-coordinate-xcoordinate
voxel-direction-dxneighbor
world-coordinate-xadjacent
=
+
world-coordinate-ycoordinate
voxel-direction-dyneighbor
world-coordinate-yadjacent
=
+
world-coordinate-zcoordinate
voxel-direction-dzneighbor
world-coordinate-zadjacent
*block-faces*
defmethodactivate-luvcraft-target
activate-wall-material
block-kind-nameblock
sessionhit
defgenericactivate-wall-material
namesessionhit
:documentation

Create and return the wall interaction for the material named name, or NIL.

The material vocabulary is open here the same way it is in the atlas: one EQL method per material which answers activation, so a new display-block material adds a method rather than growing a CASE.

:method
namesessionhit
declare
ignorenamesessionhit
nil
defunopen-activated-wall-display
sessionhitmaterialattach&key

Open the terminal display for the material wall hit names and attach it.

attach receives the fresh display and gives the wall its process; if it fails, the display is taken down rather than left attached to nothing. class is the display class to make, for walls that are not shells.

let*
coordinate
block-ray-hit-coordinatehit
whenface
let
displaynil
completed-pnil
unwind-protect
progn
setfdisplay
open-terminal-displaysession
world-coordinate-xcoordinate
world-coordinate-ycoordinate
world-coordinate-zcoordinate
block-face-nameface
:fixture"":materialmaterial:classclass
funcallattachdisplay
setfcompleted-pt
display
unlesscompleted-p
whendisplay
defmethodactivate-wall-material
name
eql:terminal
hit
defunattach-terminal-display-shell
display

Attach an interactive login-free bash in the checkout to display.

The shell learns where this game's portal server listens and which wall it is on, so a luvcraft started in it appears right here.

let
environment
cons"BASH_SILENCE_DEPRECATION_WARNING=1"
delete-if
lambda
entry
uiop:string-prefix-p"BASH_SILENCE_DEPRECATION_WARNING="entry
copy-list
sb-ext:posix-environ
session
terminal-display-sessiondisplay
#+darwin (when session (register-luvcraft-portal-screen session (terminal-display-name display) (lambda (mirror) (open-terminal-display-portal display mirror))) (setf environment (luvcraft-portal-environment session (terminal-display-name display) environment)))
attach-terminal-display-ptydisplay

The dev shell names its interactive Bash explicitly; outside it, open-pty-device resolves the fallback through the child environment.

:program
or
uiop:getenv"LUV_BASH"
"bash"
:directory
uiop:getcwd
:environmentenvironment
defunattach-terminal-display-pty
display&restopen-arguments

Attach one owned PTY device to display's existing Ghostty terminal.

check-typedisplayterminal-display
when
terminal-display-devicedisplay
error"Terminal display ~S already has an input device."display
let
arguments
copy-listopen-arguments
remfarguments:on-output
setf
terminal-display-devicedisplay
apply#'termdev:open-pty-device
terminal-display-terminaldisplay
:on-output
lambda
devicebytes
declare
ignoredevicebytes
setf
terminal-display-dirty-pdisplay
t
arguments
display
defunterminal-grid-size-for-surface
surfacefont-pathnamemarginrows-per-block

Choose columns and rows so the font grid fills surface at rows-per-block.

The row count follows the wall's block height; the column count is whatever that cell height affords across the wall's width at the font's own aspect.

terminal-grid-columns-for-rowssurfacefont-pathnamemargin
max1
round
*rows-per-block
terminal-surface-heightsurface
defunterminal-grid-columns-for-rows
surfacefont-pathnamemarginrows

Return the columns rows of FONT afford across surface, and rows.

zpb-ttf:with-font-loader
font-loaderfont-pathname
multiple-value-bind
font-heightfont-advance
let*
available-height
available-width
cell-height
/available-heightrows
cell-width
*cell-height
/font-advancefont-height
columns
max1
flooravailable-widthcell-width
valuescolumnsrows
defunopen-terminal-display
sessionxyzface&keycolumnsrows
rows-per-block6
material*terminal-block*
margin0.12

Attach a deterministic Ghostty terminal to an authored block rectangle.

X,Y,Z names any block in the desired exposed face. The maximal coplanar terminal-material component must be rectangular. Its native block meshes remain the display body; this overlay contributes only one fitted Slug grid. When columns or rows is omitted the grid is sized to the wall itself at rows-per-block rows per block height.

multiple-value-bind
surfacestatus
find-terminal-surface
luvcraft-session-worldsession
xyzface:materialmaterial
unlesssurface
error"Cannot open terminal display at (~D ~D ~D) ~S: ~S."xyzfacestatus
multiple-value-bind
fitted-columnsfitted-rows
terminal-grid-size-for-surfacesurfacefont-pathnamemarginrows-per-block
setfcolumns
orcolumnsfitted-columns
rows
orrowsfitted-rows
make-terminal-displaysessionsurfacecolumnsrows:classclass:fixturefixture:marginmargin:font-scalefont-scale:font-pathnamefont-pathname:bold-font-pathnamebold-font-pathname:default-foregrounddefault-foreground
defunmake-terminal-display
sessionsurfacecolumnsrows&key
margin0.12
screen-role:terminal-screen
faceplate-role:terminal-faceplate
add-pt

Build a columns by rows Ghostty terminal display of class on surface.

surface is anything answering the terminal-surface protocol: a wall of blocks or a phone screen. screen-role and faceplate-role name the shader materials of the panel behind the text and the glass in front of it; the defaults are the wall's tube. The display is added to session's overlays unless add-p is false.

let
glyph-cachenil
glyph-runnil
cell-runnil
screen-runnil
faceplate-runnil
displaynil
transferred-pnil
completed-pnil
unwind-protect
progn
setfterminal
ghostty:make-terminal:columnscolumns:rowsrows
let*
domain
make-instance'terminal-grid-domain:columnscolumns:rowsrows
presentation
progn
setf
ghostty:terminal-screen-default-foregroundscreen
default-foreground
glyphs-by-character
make-hash-table:test#'equal
setfglyph-cache
luv.slug:make-slug-glyph-cache
luvcraft-session-devicesession
multiple-value-setq
glyph-runcell-run
make-terminal-display-glyph-runsessionpresentationsurfaceglyph-cacheglyphs-by-characterfont-pathnamebold-font-pathnamemarginfont-scale
setfscreen-run
make-terminal-cell-runsessionglyph-run:rolescreen-role:vertex-role:terminal-screen:label"terminal screen panel"
setffaceplate-run
make-terminal-cell-runsessionglyph-run:rolefaceplate-role:vertex-role:terminal-screen:label"terminal faceplate glass"
setfdisplay
make-instanceclass:sessionsession:surfacesurface:terminalterminal:presentationpresentation:glyph-cacheglyph-cache:glyph-runglyph-run:cell-runcell-run:screen-runscreen-run:faceplate-runfaceplate-run:font-pathnamefont-pathname:bold-font-pathnamebold-font-pathname:default-foregrounddefault-foreground:marginmargin:font-scalefont-scale
setf
slot-valuedisplay'glyphs-by-character
glyphs-by-character
whenadd-p

ADD consumes DISPLAY on either success or terminal rejection; the local resource variables no longer own it.

setftransferred-pt
add-luvcraft-overlaysessiondisplay
setfcompleted-pt
display
unless
orcompleted-ptransferred-p
whenfaceplate-run
ignore-errors
whenscreen-run
ignore-errors
whencell-run
ignore-errors
whenglyph-run
ignore-errors
whenglyph-cache
ignore-errors