Blink text
Text printed a character at a time, with a blinking cursor and longer pauses at punctuation. Feed it a finished string or a stream.
Typing
A full paragraph, so the pauses are visible at work: longer at a full stop than at a comma, which is what makes it read like speech rather than a ticker. The text below it does not move as the passage types, because PreserveSpace holds the finished footprint. SkipOnClick lets an impatient reader click the text to finish it.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur; excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
This paragraph sits below the one being typed, and stays exactly where it is.
<VetoBlinkText Text="Initialising the component library."
CharactersPerSecond="34"
OnCompleted="OnDone" />
<VetoButton OnClick="Restart">Run it again</VetoButton>
@code {
private int _run;
private bool _done;
// Changing the text is what restarts the reveal.
private void Restart() { _run++; _done = false; }
private void OnDone() => _done = true;
}Scramble
A few glyphs flicker ahead of the cursor before settling into the real characters - the effect the falling-code screens are known for. The scramble is never longer than the text still to come, so it cannot imply more than there is.
Wake up, Neo... The Matrix has you.
<VetoBlinkText Text="Wake up, Neo... The Matrix has you."
CharactersPerSecond="16"
Scramble="true"
Loop="true"
CursorCharacter="_" />From a stream
Give it an IAsyncEnumerable and chunks are appended as they arrive, then drained at the reveal rate. Text from a slow or uneven source reads at a steady pace instead of landing in lurches - which is the difference between a model's output looking considered and looking stuck.
Waiting…
<VetoBlinkText Stream="_stream" CharactersPerSecond="60" PreserveSpace="false" />
<VetoButton OnClick="Start">Start streaming</VetoButton>
@code {
private IAsyncEnumerable<string>? _stream;
private void Start() => _stream = Client.StreamAsync(prompt);
}Where it pauses
PauseOn maps a character to extra milliseconds. Pass your own to pause on anything - a pipe between fields, a slash in a path, a full stop you want to linger on.
scanning | 12 hosts | 3 open ports | done
By word instead of by character, for longer passages:
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos.
<VetoBlinkText Text="scanning | 12 hosts | 3 open ports | done"
CharactersPerSecond="70"
PauseOn="@(new Dictionary<char, int> { ['|'] = 600 })"
Loop="true" />
<VetoBlinkText Text="One word at a time reads faster."
ByWord="true"
CharactersPerSecond="7" />What a screen reader gets
The whole text, once. The animated copy is hidden from assistive technology and a
clipped copy of the finished text sits alongside it - announcing a character at a
time would be unusable. Under prefers-reduced-motion the text appears
complete and the cursor stops blinking: the motion is the decoration, the text is
the content.
PreserveSpace holds the finished text's footprint while it types, so a
paragraph does not reflow line by line and shove the page around beneath it. It needs
a known length, so it applies to Text rather than Stream.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
Text |
string? |
null |
The text to reveal. Changing it restarts the reveal. |
Stream |
IAsyncEnumerable<string>? |
null |
Chunks appended as they arrive, drained at the reveal rate. |
CharactersPerSecond |
double |
45 |
How fast the text appears. |
ByWord |
bool |
false |
Reveal whole words rather than single characters. |
PauseOn |
IReadOnlyDictionary<char, int> |
commas and sentence ends |
Extra milliseconds after particular characters. |
StartDelay |
int |
0 |
Milliseconds to wait before starting. |
Cursor / CursorCharacter |
bool / string |
true / "▋" |
The blinking cursor. |
CursorWhenComplete |
bool |
false |
Whether the cursor stays once finished. |
Scramble |
bool |
false |
Flicker random glyphs ahead of the cursor. |
ScrambleLength |
int |
3 |
How many glyphs flicker. |
ScrambleCharacters |
string |
katakana and digits |
The glyphs used while scrambling. |
Loop / LoopDelay |
bool / int |
false / 1600 |
Start again once complete, after a hold. |
PreserveSpace |
bool |
true |
Hold the finished text's space so the layout does not reflow. Text only. |
Instant |
bool |
false |
Show the text immediately, skipping the reveal. |
SkipOnClick |
bool |
false |
A click on the text finishes the reveal at once. Skip() does the same from code. |
OnCompleted |
EventCallback |
— |
Raised once the whole text has been revealed - for a stream, once it has ended and been drained. |