Skip to main content

CodeBlock (Deprecated)

caution

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
);
tip

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;