CodeBlock (Deprecated)
CodeBlock
has been deprecated and will be removed in version 4. Please use the
new Code
node instead.
The CodeBlock
component is used to present syntax highlighted code. It can
automatically highlight many common languages. That code can then be modified in
place to present changes to the viewer. Modified code will animate from the
prior code to the new code by removing old code, translating the remaining code,
and inserting new code. You may also "select" code in order to call attention to
important snippets.
Using the component
To display code, set the code
and language
property.
import {CodeBlock} from '@motion-canvas/2d/lib/components/CodeBlock';
yield view.add(
<CodeBlock language="c#" code={`Console.WriteLine("Hello World!")`} />,
);
You can find a list of available languages in the Starry Night
repository—the library used for syntax highlighting. The default language is
tsx
, the language of Motion Canvas, which we will use for the rest of this
guide.
Note that unlike most components, you must yield
any call to add
which
includes a CodeBlock
. This prompts Motion Canvas to prepare the syntax
highlighter.
yield view.add(<CodeBlock />);
Indentation
For convenience, the indentation of code will be automatically adjust whenever the code starts with a new line.
import {CodeBlock} from '@motion-canvas/2d/lib/components/CodeBlock';
yield view.add(
// note that the ` bracket is followed by a new line
<CodeBlock
code={`
console.log('Hello World!')
// more indented
// less indented`}
/>,
);
console.log('Hello World!');
// more indented
// less indented
The indentation is then set by the least indented code.
import {CodeBlock} from '@motion-canvas/2d/lib/components/CodeBlock';
yield view.add(
// note that the ` bracket is followed by a new line
<CodeBlock
code={`
console.log('Hello World!')
// less indented
// more indented`}
/>,
);
console.log('Hello World!');
// less indented
// more indented
Selection
Code may be "selected" to call attention to it. The default behavior is to desaturate any unselected text.
Using Helpers
You can define the selection with the help of three helper functions — range
,
word
and lines
.
import {CodeBlock} from '@motion-canvas/2d/lib/components/CodeBlock';
import {createRef} from '@motion-canvas/core';
const codeBlockRef = createRef<CodeBlock>();
yield view.add(
<CodeBlock ref={codeBlockRef} code={`...`} selection={range(0, 2, 0, 4)} />,
);
// or
yield codeBlockRef.selection(range(0, 2, 0, 4));
range
expects 4 parameters: the starting line, starting character offset,
ending line and ending character offset. Do note however that all values are
zero-indexed. So if you want to select a 5 character long word on the first
line that has another 4 characters before it, you would use the following call:
range(
0, // starting on the first line
4, // starting with the 5th character
0, // ending on the first line
8, // ending with the 9th character
);
For this specific use case there is however another helper, word
. It expects
2-3 parameters - the starting line and character offset, aswell as an optional
word length.
The aforementioned range
-Example could be rewritten as follows using the
word
-Helper:
word(
0, // starting on the first line
4, // starting with the 5th character,
5, // the selection will have a total of 5 chars, can be ommited, which will select the remainder of this line
);
Do note that the word
-Helper can only be applied on a per-line basis.
Finally, you can use the lines
function to select whole lines of code. The
following will select the 5th up to the 10th line:
lines(
4, // starting line
9, // ending line, can be ommited, which will only select the starting line
);
You can also mix and match helpers by using the spread operator!
You could select the 3rd line and a 10 character long word on the 5th line starting at the 6th character using the following expression:
yield * codeRef().selection([...lines(2), ...word(4, 5, 10)], 1);
If you wish to undo a selection, you can either select all lines from 0
to
Infinity
, or simply pass DEFAULT
as a selection, as shown below:
import {DEFAULT} from '@motion-canvas/core';
// highlight lines 1 and 2
yield * codeRef().selection(lines(1, 2), 1);
// highlight all lines
yield * codeRef().selection(DEFAULT, 1);
Raw Usage
Under the hood the helpers return a nested array which defines multiple selections using two tuples, each defining a line and character offset per selection.
<CodeBlock
selection={[
[
// First selection
[lineFrom, characterFrom],
[lineTo, characterTo],
],
[
// Second selection
[lineFrom, characterFrom],
[lineTo, characterTo],
],
[
//... etc
],
]}
/>
lines(4,7)
will for example return the following structure:
[
[
[4, 0],
[7, Infinity],
],
];
Animating code
You may insert, remove, or edit the displayed code, any of which will animate
the code to its new state. All of these changes are performed with the edit
method on a CodeBlock
instance.
To insert code, start by using createRef
to store your CodeBlock
instance
for future edits. Then call edit
with an embedded insert
call to add the new
code.
import {CodeBlock, insert} from '@motion-canvas/2d/lib/components/CodeBlock';
import {createRef} from '@motion-canvas/core';
const codeRef = createRef<CodeBlock>();
yield view.add(<CodeBlock ref={codeRef} code={`var myBool;`} />);
// duration of 1.2 seconds
yield * codeRef().edit(1.2)`var myBool${insert(' = true')};`;
var myBool;
// will animate to
var myBool = true;
Removing code is similar, only with the provided code being removed during the animation.
import {CodeBlock, remove} from '@motion-canvas/2d/lib/components/CodeBlock';
yield view.add(<CodeBlock ref={codeRef} code={`var myBool = true;`} />);
yield * codeRef().edit(1.2)`var myBool${remove(' = true')};`;
var myBool = true;
// will animate to
var myBool;
Finally, replacing code combines removal and insertion into one call.
yield view.add(<CodeBlock ref={codeRef} code={`var myBool = true;`} />);
yield * codeRef().edit(1.2)`var myBool = ${edit('true', 'false')};`;
var myBool = true;
// will animate to
var myBool = false;
Editing code will update your selection to highlight the changes. If you would
like to retain your selection through an animation, use edit(duration, false)
.
yield view.add(<CodeBlock ref={codeRef} code={`var myBool;`} />);
// note the second argument to edit
yield * codeRef().edit(1.2, false)`var myBool${insert(' = true')};`;
You may apply multiple edits to a code block over the course of a video, each modifying the prior code to a new state.
yield view.add(<CodeBlock ref={codeRef} code={`var myBool;`} />);
yield * codeRef().edit(1.2)`var myBool${insert(' = true')};`;
yield * waitFor(1);
yield * codeRef().edit(1.2)`var myBool = ${edit('true', 'false')};`;
yield * waitFor(1);
yield * codeRef().edit(1.2)`var myBool${remove(' = false')};`;
The proceeding code will animate through
var myBool;
var myBool = true;
var myBool = false;
var myBool;
You can also apply multiple changes to a code block in one edit
, such that all
changes are applied simultaneously.
yield view.add(<CodeBlock ref={codeRef} code={`var myBool;`} />);
yield *
codeRef().edit(1.2)`${edit('var', 'const')} myBool${insert(' = true')};`;
var myBool;
// will animate to
const myBool = true;