Install
That writes one file:compositions/components/typewriter.html.
Variables
Every one of these has a default, so the piece works untouched. Set the ones you want to change on the element:| Variable | Default | Accepts | What it does |
|---|---|---|---|
text | hyperframes add typewriter | string | Line that types itself out character by character. |
tone | ink | ink, paper, accent | Colour of the text and the caret: ink for light frames, paper for dark ones, accent rides —brand. |
caret | line | line, block, none | Caret shape: a thin rule, a terminal-style block, or no caret at all. |
data-variable-values on the element that mounts it. These are the
defaults, so this behaves exactly like the preview above until you change one:
<div
data-composition-id="typewriter"
data-composition-src="compositions/components/typewriter.html"
data-variable-values='{"text":"hyperframes add typewriter","tone":"ink","caret":"line"}'
></div>
Source
typewriter.html
typewriter.html
<!--
Typewriter - remocn typography primitive for HyperFrames.
Paste the markup, CSS and script into a composition. Drive the timeline
integration from a paused GSAP timeline so renders remain deterministic.
Variables. The script reads each one, falls back to the declared default on
anything missing or unrecognised, and writes the result either into the
markup or into a custom property the CSS above consumes. The timeline recipe
below is untouched by them: it keeps driving one type progress and one caret
opacity, and these decide what is typed, in what colour, and behind which
caret.
- text (string, default hyperframes add typewriter): the line that types
itself out. It is written into the existing span, so the reveal keeps
running character by character over whatever is set. Anything that is
not a non-empty string keeps the shipped line.
- tone (ink | paper | accent, default ink): colour of both the text and
the caret. ink is near-black for light frames, paper near-white for dark
ones, accent rides --brand.
- caret (line | block | none, default line): caret shape. line is the
shipped 3px rule, block is a 22px slab in the style of a terminal
cursor, none removes the caret entirely and closes the gap after the
text.
On every default the result is identical to the original: a near-black
monospace line typing itself out behind a 3px caret.
-->
<div
class="hf-remocn-typewriter"
data-composition-variables='[
{ "id": "text", "type": "string", "role": "content", "label": "Text", "description": "Line that types itself out character by character.", "default": "hyperframes add typewriter" },
{ "id": "tone", "type": "enum", "role": "style", "label": "Tone", "description": "Colour of the text and the caret: ink for light frames, paper for dark ones, accent rides --brand.", "default": "ink", "options": [{ "value": "ink", "label": "Ink" }, { "value": "paper", "label": "Paper" }, { "value": "accent", "label": "Accent" }] },
{ "id": "caret", "type": "enum", "role": "style", "label": "Caret", "description": "Caret shape: a thin rule, a terminal-style block, or no caret at all.", "default": "line", "options": [{ "value": "line", "label": "Line" }, { "value": "block", "label": "Block" }, { "value": "none", "label": "None" }] }
]'
>
<span>hyperframes add typewriter</span><i></i>
</div>
<style>
.hf-remocn-typewriter {
color: var(--hf-type-color, #18181b);
font-family: Inter, system-ui, sans-serif;
font-weight: 900;
letter-spacing: -0.04em;
}
.hf-remocn-typewriter {
display: inline-flex;
align-items: center;
gap: 4px;
font:
800 42px/1 ui-monospace,
SFMono-Regular,
Menlo,
monospace;
}
.hf-remocn-typewriter span {
display: inline-block;
max-width: calc(var(--hf-type-progress, 1) * 100%);
overflow: hidden;
white-space: nowrap;
}
.hf-remocn-typewriter i {
display: var(--hf-caret-display, block);
width: var(--hf-caret-width, 3px);
height: 42px;
border-radius: 999px;
background: var(--hf-type-color, #18181b);
opacity: var(--hf-caret-opacity, 1);
}
</style>
<script>
(function () {
"use strict";
var vars =
window.__hyperframes && window.__hyperframes.getVariables
? window.__hyperframes.getVariables()
: {};
// Unrecognised overrides return to their declared defaults.
var tones = {
ink: "#18181b",
paper: "#fafafa",
accent: "var(--brand, #34d399)",
};
var carets = {
line: { width: "3px", display: "block" },
block: { width: "22px", display: "block" },
none: { width: "3px", display: "none" },
};
function pick(table, value, fallback) {
return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
}
var tone = tones[pick(tones, vars.tone, "ink")];
var caret = carets[pick(carets, vars.caret, "line")];
var text = typeof vars.text === "string" && vars.text !== "" ? vars.text : null;
var roots = document.querySelectorAll(".hf-remocn-typewriter");
for (var i = 0; i < roots.length; i += 1) {
var root = roots[i];
root.style.setProperty("--hf-type-color", tone);
root.style.setProperty("--hf-caret-width", caret.width);
root.style.setProperty("--hf-caret-display", caret.display);
var line = root.querySelector("span");
if (text !== null && line) {
line.textContent = text;
}
}
})();
</script>
<!--
Timeline integration:
tl.fromTo('.hf-remocn-typewriter', { '--hf-type-progress': 0 }, { '--hf-type-progress': 1, duration: 1.2, ease: 'steps(28)' }, startTime); tl.to('.hf-remocn-typewriter i', { '--hf-caret-opacity': 0.2, duration: 0.24, repeat: 7, yoyo: true, ease: 'none' }, startTime + 0.2);
-->
Usage
Opencompositions/components/typewriter.html and paste its contents into your composition. See the comment header in the file for detailed instructions.
Tagged video-primitive motion-primitive remocn-port typography.