See also: Star Wars ASCIImation (through telnet), Popcorn.js interaction
Terminals have sizes
If you ue termrec
to record, the size of the terminal is stored:
<tty-player controls src=sized.ttyrec></tty-player>
Where dimensions are not specified, the terminal defaults to 80 columns and 24 rows.
This demo also shows the controls
attribute; the design of the controls is modelled fairly closely after Firefox’s controls for <video>
.
Using data:
URIs
The ttyrec
format being binary, using base64 encoding is the easiest way. I’ve gone with the application/x-ttyrec
MIME type, but it really doesn’t matter what you choose.
(This demo also shows the autoplay
and loop
attributes.)
<tty-player autoplay loop src="data:application/x-ttyrec;base64,
AAAAAAttCwCBAAAAG1sxbRtbN20lG1syN20bWzFtG1ttICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgDSANAAAAACNtCwAXAAAAG10yO2NocmlzQGR1b25leDog
L3RtcAcAAAAAZDsMAC4AAAANG1ttG1syN20bWzI0bRtbSg0KG1swMTszMm0bWzQ1bS90bXAbWzAw
bSQgG1tLAAAAAJk7DAACAAAAGz0DAAAAg4QBAAEAAABwAwAAAOSsAgADAAAACHBhAwAAAOI2BAAB
AAAAYwMAAADmNAcAAQAAAGEDAAAA6voIAAEAAAB1AwAAAFxvCgABAAAAcgMAAADNDQwAAQAAACAD
AAAARQAOAAEAAAAtBAAAAE4/AgABAAAAUwQAAACEZwUAAQAAAHMEAAAARmcHAAEAAAAgBAAAALt4
CwABAAAAdAQAAACvtA0AAQAAAHQEAAAA29oOAAEAAAB5BQAAAGhKAgABAAAAcgUAAADOlwMAAQAA
AGUFAAAAOiIGAAEAAABjBQAAAH5RCQAbAAAAGz4NDQobXTI7cGFjYXVyIC1TcyB0dHlyZWMHBwAA
AOoECACKAwAAG1sxOzM1bWF1ci8bWzBtG1sxbXR0eXJlYyAbWzE7MzJtMS4wLjgtMhtbMG0gKDM0
KQ0KICAgIEEgdHR5IHJlY29yZGVyIGFuZCBwbGF5ZXINChtbMTszNW1hdXIvG1swbRtbMW10ZXJt
cmVjIBtbMTszMm0wLjE3LTEbWzBtICgxMSkNCiAgICBBIHNldCBvZiB0b29scyBmb3IgcmVjb3Jk
aW5nL3JlcGxheWluZyB0ZXh0LXRlcm1pbmFsIHNlc3Npb24sIGluIHRoZSB2ZWluIG9mIHR0eXJl
Yy4NChtbMTszNW1hdXIvG1swbRtbMW1wbGF5dHR5cmVjIBtbMTszMm0xLjAtMxtbMG0gKDYpDQog
ICAgYSBwbGF5ZXIgZm9yIHJlY29yZGVkIG5ldGhhY2sgZ2FtZXMgcHJvZHVjZWQgYnkgZGdhbWVs
YXVuY2gNChtbMTszNW1hdXIvG1swbRtbMW10dHlnaWYgG1sxOzMybTEuMC44LTIbWzBtICg2KQ0K
ICAgIEEgdG9vbCB0aGF0IGNvbnZlcnRzIGEgdHR5cmVjIGZpbGUgaW50byBnaWYgZmlsZXMuDQob
WzE7MzVtYXVyLxtbMG0bWzFtaXBidCAbWzE7MzJtMjAxNDEwMjYuMjE5NzQzMi0xG1swbSAoNCkN
CiAgICBBIGhpZ2gtdGVjaCB0dHlyZWMgcGxheWVyDQobWzE7MzVtYXVyLxtbMG0bWzFtdHR5cmVj
LWdpdCAbWzE7MzJtMjAxMzA5MTgtMRtbMG0gKDQpDQogICAgQSB0dHkgcmVjb3JkZXIgYW5kIHBs
YXllciAtIHRoaXMgaXMgbm90IHRoZSBvZmZpY2lhbCB1cHN0cmVhbSB2ZXJzaW9uDQobWzE7MzVt
YXVyLxtbMG0bWzFtc2VxMmdpZiAbWzE7MzJtMC4xMC40LTEbWzBtICgxKQ0KICAgIENvbnZlcnQg
YSB0dHlyZWMgcmVjb3JkIGludG8gYSBnaWYgYW5pbWF0aW9uIGRpcmVjdGx5DQobWzE7MzVtYXVy
LxtbMG0bWzFtc2VxMmdpZi1naXQgG1sxOzMxbTAuMTAuMy4xODIuMjUzZGFjYi0xG1swbSAoMCkN
CiAgICBDb252ZXJ0IGEgdHR5cmVjIHJlY29yZCBpbnRvIGEgZ2lmIGFuaW1hdGlvbiBkaXJlY3Rs
eQ0KBwAAAOsGCACYAAAAG1sxbRtbN20lG1syN20bWzFtG1ttICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgDSANG10yO2NocmlzQGR1b25leDogL3RtcAcHAAAA
x7wIADAAAAANG1ttG1syN20bWzI0bRtbSg0KG1swMTszMm0bWzQ1bS90bXAbWzAwbSQgG1tLGz0I
AAAAnV8IAAMAAAANDQo="></tty-player>
The poster
<video poster>
is the URL for an image to display before the video is played; its intent is to give the impression of what the video is about.
<tty-player poster>
works on the same principles, but with some differences:
- Images aren’t actually supported at present; just as the poster is typically a frame of the video, images seem less likely to be desirable/useful here. Still, image support will probably come eventually. (In fact, for certain reasons any poster text may well be rasterised.)
- You can specify as the poster a frame from the recording itself by using the
npt:
URL scheme. As it uses NPT, values like 16.54
, 4:13
and 1:03:45.678
will all work.
- You can specify arbitrary plain text (control sequences will be evaluated) with
data:
URIs of the text/plain
type. (This is demonstrated in the Star Wars example.)
<tty-player controls src=vim.ttyrec poster=npt:16.54></tty-player>
Errors
When the src
attribute (or property) is set to something that isn’t a ttyrec file (either it doesn’t exist or it’s something else), the error
property is set appropriately and the simple error
event fired, just like with any other media element; there’s a nifty little error displayer included as seen below.
This demo also demonstrates the rows
and cols
attributes (mirrored as properties, of course). As mentioned earlier, if you use termrec
to record your ttyrec scripts, it records the terminal dimensions in the file it writes; where both are specified, the recording wins and the attributes are ignored.
<tty-player src=non-existent-file cols=72 rows=7></tty-player>
Pretending to be a <video>
<tty-player>
implements all of the HTMLMediaElement
interface, but it doesn’t implement all of HTMLVideoElement
(specifically, it does not implement width
, height
, videoWidth
and videoHeight
). Oh, and its tagName
is "TTY-PLAYER"
instead of "VIDEO"
. Thus, although it can mostly just be dropped in where a <video>
is expected, it can’t entirely by default.
Occasionally what is normally close enough isn’t sufficient; for such cases there is a method that patches the differences up: HTMLTTYPlayerElement.pretendToBeAVideo()
.
To demonstrate this, we can call that method on all of the TTY players on this page and turn them into MediaElement.js players, and it Just Works™:
You may notice that this is not perfect at present; most notably, the handling of the poster chrome, errors and maybe resizing leave something to be desired. These should be fixed, but they’re fairly low priority for me at present.
MediaElement.js will probably also mess things up on browsers that don’t support <video>
.
IDL attributes, events and such
The element implements the contents of the HTMLMediaElement interface plus a bit of the HTMLVideoElement interface. This means that you have properties (defined as IDL attributes) like currentSrc
, loop
and playbackRate
. That last one is a particularly fun one. It’s also got a few additional properties of its own.
Want to see all the events as they get fired, show all the IDL attributes and let you tweak it all? That “Show internals” checkbox in the header does it. (Compare with a similar arrangement on <video>
.) Bear in mind that this only applies from the point when the things are added; any events before that time won’t be counted.
Try a negative playbackRate—it works, though it’s rather inefficient (when playing backwards, each frame requires resetting the terminal and writing to that point again, which makes it very expensive for anything but small scripts; it probably works fine for this one)
Large scripts
Large scripts should work fine for playing, though there is no streaming. (XMLHttpReqest doesn’t do streaming and I haven’t determined what else might be able to be done yet.) This simplifies various things internally, but makes large scripts less convenient.
I recorded a 80×24 Vim session that lasted for an hour and a half while I was taking notes on a documentary film (Evolution’s Achilles’ Heel); this produced a 3MB ttyrec file containing 26,389 chunks; gzipped, it’s under 400KB, showing that enabling gzipping of the resource on the server gets a very good return.
Because rendering from start to end is such heavy work, the entire playback will never on my machine go under about 9 seconds, regardless of how high playbackRate
is set; this has the effect that panning backwards is prohibitively slow, because it has to play back the entire script from the start; this could in the future be ameliorated by the introduction of keyframes, freezing the relevant state every so often and, rather than rendering from the start render from the latest keyframe. That would either be something that the client could introduce, making the first visit to a point slow but thereafter fast, or some extension of the ttyrec format, increasing size and requiring processing of files to introduce the keyframes.
Just like <video>
and <audio>
, <tty-player>
can have preload=none
, which will cause it to hold off on downloading the script until it needs to.
Do not combine preload=none
with poster=npt:…
; the latter will negate the former (actually, at present it’s implemented badly and poster
won’t work at all with preloading disabled until load()
is called).
<tty-player src=evolutions-achilles-heel-notetaking.ttyrec preload=none controls></tty-player>