Script your coding demos to perfection with this VS Code extension – no typos, no missteps, just flawless, stress-free presentations every time. Execute each demo step seamlessly, just like advancing through a presentation!
Features
Currently, the extension supports the following features:
- Highlighting code in a file.
- Multiple demo files located in the
.demo
folder.
- Support for code/snippet files in the
.demo
folder, allowing you to define multiple reusable steps.
- Explorer panel to execute your demo steps (you can move it to the activity bar).
- Run through the demo steps by executing the
Demo Time: Start
command.
- Presentation mode that allows you to use a clicker to navigate through the demo steps.
- Run a specific demo step from a command execution using the
demo-time.runById
command.
- Place your variables in a
variables.json
file in the .demo
folder and reference them like {variable_name}
in your demo steps.
- Detachable presenter view which you can move to a different screen.
- Adding notes to your demo steps.
Usage
To use the extension, you need to create a .demo
folder in your workspace. Once created, you can add a JSON file which contains the demo and its steps.
{
"$schema": "https://demotime.elio.dev/demo-time.schema.json",
"title": "<title>",
"description": "<description>",
"demos": []
}
Add your demos to the demos
array. Each demo can consist of multiple steps.
{
"title": "<title>",
"description": "<description>",
"steps": []
}
You can also add "icons" to your demo steps to make them more recognizable. You can use the following icons:
{
"title": "<title>",
"description": "<description>",
"icons": {
"start": "<name of the icon (optional)>",
"end": "<name of the icon (optional)>"
},
"steps": []
}
Use the icon names you can find in the icon listing from the Visual Studio Code documentation.
Demo steps
File actions
Find more information on the file actions documentation page.
Action |
Description |
Usage |
create
|
Create a new file
|
{
"action": "create",
"path": "<relative path to the file>",
"content": "<content of the file> (optional)",
"contentPath": "<relative path to the file in the .demo folder> (optional)"
}
|
open
|
Open a file
|
{
"action": "open",
"path": "<relative path to the file>"
}
|
markdownPreview
|
Preview a Markdown file
|
{
"action": "markdownPreview",
"path": "<relative path to the file>"
}
|
save
|
Save the current active file
|
{
"action": "save"
}
|
rename
|
Rename a file
|
{
"action": "rename",
"path": "<relative path to the file>",
"dest": "<new file name/path>"
}
|
deleteFile
|
Delete a file
|
{
"action": "deleteFile",
"path": "<relative path to the file>"
}
|
close
|
Close the current active file
|
{
"action": "close"
}
|
closeAll
|
Close all open files
|
{
"action": "closeAll"
}
|
Text actions
Find more information on the text actions documentation page.
Action |
Description |
Usage |
insert
|
Insert code into a file
|
// Via position
{
"action": "insert",
"path": "<relative path to the file>",
"position": "<position>",
"content": "<content of the file> (optional)",
"contentPath": "<relative path to the file in the .demo folder> (optional)",
"lineInsertionDelay": "<delay in milliseconds to insert each line> (optional)"
}
// Via placeholders
{
"action": "insert",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
"endPlaceholder": "<end placeholder>",
"content": "<content of the file> (optional)",
"contentPath": "<relative path to the file in the .demo folder> (optional)",
"lineInsertionDelay": "<delay in milliseconds to insert each line> (optional)"
}
|
replace
|
Replace code in a file
|
// Via position
{
"action": "replace",
"path": "<relative path to the file>",
"position": "<position>",
"content": "<content of the file> (optional)",
"contentPath": "<relative path to the file in the .demo folder> (optional)",
"lineInsertionDelay": "<delay in milliseconds to insert each line> (optional)"
}
// Via placeholders
{
"action": "replace",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
"endPlaceholder": "<end placeholder>",
"content": "<content of the file> (optional)",
"contentPath": "<relative path to the file in the .demo folder> (optional)",
"lineInsertionDelay": "<delay in milliseconds to insert each line> (optional)"
}
|
delete
|
Delete code from a file
|
// Via position
{
"action": "delete",
"path": "<relative path to the file>",
"position": "<position>"
}
// Via placeholders
{
"action": "delete",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
"endPlaceholder": "<end placeholder>"
}
|
highlight
|
Highlight code in a file. Check out the settings section to customize the highlight colors.
|
// Via position
{
"action": "highlight",
"path": "<relative path to the file>",
"position": "<position>",
"zoom": "<zoom level> (optional)"
}
// Via placeholders
{
"action": "highlight",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
"endPlaceholder": "<end placeholder>",
"zoom": "<zoom level> (optional)"
}
|
positionCursor
|
Postion the cursor at a specific line and character position
|
// Via position
{
"action": "positionCursor",
"path": "<relative path to the file>",
"position": "<position>"
}
// Via start placeholder
{
"action": "positionCursor",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
}
|
unselect
|
Unselect code in a file
|
{
"action": "unselect",
"path": "<relative path to the file>"
}
|
write
|
Write a single line of text to the editor
|
// Write to current active position
{
"action": "write",
"content": "Hello World"
}
// Write to a specific position in a file
// Via position
{
"action": "write",
"content": "Hello World",
"path": "<relative path to the file>",
"position": "<position>"
}
// Via start placeholder
{
"action": "write",
"content": "Hello World",
"path": "<relative path to the file>",
"startPlaceholder": "<start placeholder>",
}
|
format
|
Format the content of the active file
|
{
"action": "format"
}
|
Patch actions
Find more information on the patch actions documentation page.
Similar to the Text actions, the patch actions can be used to update the contents of a file, but you do not need to specify the position of the text to insert. Instead, you need to create a snapshot of the file and a patch file.
A patch works like a git’s diff functionality, but instead of requiring a git branch, the base file is stored as a snapshot in the .demo/snapshots
folder, and the patch file is stored in the .demo/patches
folder.
Action |
Description |
Usage |
applyPatch
|
Apply a patch to a file
|
{
"action": "applyPatch",
"path": "<relative path to the file>", // This will be the source file to update
"contentPath": "<relative path to the snapshot file in the .demo folder>",
"patch": "<relative path to the patch file in the .demo folder>"
}
|
Setting actions
Find more information on the setting actions documentation page.
Action |
Description |
Usage |
setSetting
|
Update a setting in Visual Studio Code
|
{
"action": "setSetting",
"setting": {
"key": "<setting key>",
"value": "<value>"
}
}
|
setTheme
|
Update the current theme
|
{
"action": "setTheme",
"theme": "<theme name>"
}
|
unsetTheme
|
Reset the current theme
|
{
"action": "unsetTheme"
}
|
Setting update example
Here is an example of how you can hide the activity and status bar in Visual Studio Code.
{
"action": "setSetting",
"args": {
"setting": "workbench.statusBar.visible",
"value": false
}
},
{
"action": "setSetting",
"args": {
"setting": "workbench.activityBar.location",
"value": "hidden"
}
}
To reset the settings, you can use the following steps:
{
"action": "setSetting",
"setting": {
"key": "workbench.statusBar.visible",
"value": null
}
},
{
"action": "setSetting",
"setting": {
"key": "workbench.activityBar.location",
"value": null
}
}
Time actions
Find more information on the time actions documentation page.
Action |
Description |
Usage |
waitForTimeout
|
Wait for a specific amount of time
|
{
"action": "waitForTimeout",
"timeout": "<timeout in milliseconds>"
}
|
waitForInput
|
Wait until the user presses a key
|
{
"action": "waitForInput"
}
|
VS Code actions
Find more information on the vscode actions documentation page.
Action |
Description |
Usage |
executeVSCodeCommand
|
Execute a VSCode command
|
{
"action": "executeVSCodeCommand",
"command": "<command to execute>",
"args": "<arguments to pass to the command (optional)>",
"path": "<relative path to the file (optional, when defined, the args property is ignored.)>"
}
|
showInfoMessage
|
Show a notification in Visual Studio Code
|
{
"action": "showInfoMessage",
"message": "<message>"
}
|
setState
|
Set a state in the extension which is cleared on startup or when you reset the demos. You can use the state value in your demo steps by using the following {STATE_<key>} syntax.
|
{
"action": "setState",
"state": {
"key": "<key>",
"value": "<value>"
}
}
|
Terminal actions
Find more information on the terminal actions documentation page.
Action |
Description |
Usage |
executeTerminalCommand
|
Execute a command in the terminal
|
{
"action": "executeTerminalCommand",
"command": "<command to execute>",
"terminalId": "<terminal id (optional)>"
}
|
executeScript
|
Execute a script in the background of which you can use the output in the next steps with {SCRIPT_<script id>} syntax.
|
{
"action": "executeScript",
"id": "<script id>",
"path": "<script to execute>",
"command": "node" // Can be powershell, bash, shell, python, etc.
}
|
closeTerminal
|
Close the terminal
|
{
"action": "closeTerminal",
"command": "<command to execute>",
"terminalId": "<terminal id (optional)>"
}
|
Snippets
Find more information on the snippet actions documentation page.
Action |
Description |
Usage |
snippet
|
Use a snippet in which you can define multiple reusable steps
|
{
"action": "snippet",
"contentPath": "<relative path to the file in the .demo folder> (optional)"
"args": {
// Define the argument name in the snippet file with curly braces {argument name}
"<argument name>": "<argument value>"
}
}
|
You can find examples of snippets in the snippets folder.
Snippet example
In the demo file, you can reference a snippet file. The snippet file can contain multiple steps which can be reused in multiple demos.
{
"action": "snippet",
"contentPath": "./snippets/insert_and_highlight.json",
"args": {
"MAIN_FILE": "sample.json",
"CONTENT_PATH": "content.txt",
"CONTENT_POSITION": "3",
"HIGHLIGHT_POSITION": "4"
}
}
The contentPath
property its value is relative to the .demo
folder. So, in the example above, the snippet file is located in the .demo/snippets
folder.
In the args
property, you can define the arguments/variables which you want to use in the snippet file. In the snippet file, you can reference these arguments with curly braces {argument name}
.
In the insert_and_highlight.json
file, you can define the steps you want to execute.
[
{
"action": "unselect",
"path": "{MAIN_FILE}"
},
{
"action": "insert",
"path": "{MAIN_FILE}",
"contentPath": "{CONTENT_PATH}",
"position": "{CONTENT_POSITION}"
},
{
"action": "highlight",
"path": "{MAIN_FILE}",
"position": "{HIGHLIGHT_POSITION}"
}
]
Settings
Setting |
Description |
Default |
demoTime.highlightBackground |
The background color of the highlighted code. |
var(--vscode-editor-selectionBackground) |
demoTime.highlightBorderColor |
The border color of the highlighted code. |
rgba(255,0,0,0.5) |
demoTime.highlightBlur |
Blur effect on the text which is not highlighted. |
0 |
demoTime.highlightOpacity |
The opacity of the text which is not highlighted. Number between 0 and 1. |
0.5 |
demoTime.highlightZoomEnabled |
Enable zooming when highlighting code. |
false | number (zoom level) |
demoTime.previousEnabled |
Enable the previous command when in presentation mode. |
false |
demoTime.showClock |
Show a clock in the status bar. |
true |
demoTime.timer |
Count down timer for how long the session should last. If not set, it will not count down. The value is the number of minutes. |
null |
demoTime.lineInsertionDelay |
The speed in milliseconds for inserting lines. If you set it to 0 , it will insert its content immediately. |
25 |
demoTime.api.enabled |
Enable the API to control the extension. |
false |
demoTime.api.port |
The port on which the API should run. |
3710 |
The demoTime.previousEnabled
is by default disabled to avoid conflicts when the previous action inserted content into a file.
When you enable this setting, you can use the Demo Time: Previous
command to go back to the previous step or use the left clicker button.
Commands
Command |
Description |
Demo Time: Start |
Starts the demo or runs the next demo step. |
Demo Time: Previous |
Go back to the previous demo step (only in presentation mode and when the demoTime.previousEnabled setting is enabled). |
Demo Time: Add as demo step |
Add the current selection as a demo step to the demo file. |
Demo Time: Reset |
Reset all the demos. |
Demo Time: Start countdown |
Start the countdown clock (you need to define the time in the demoTime.timer setting). |
Demo Time: Reset countdown |
Reset the countdown clock. |
Demo Time: Toggle presentation mode |
Toggle the presentation mode. In this mode you'll be able to use your clicker or arrow keys for the Demo Time: Start and Demo Time: Previous commands. |
Demo Time: Show presenter view |
Open the presenter view which you can detach and move to another screen while presenting. |
The Demo Time: Start
and Demo Time: Previous
commands have a keybinding assigned to them.
You can override these keybindings in your Visual Studio Code settings.
API
The extension provides an API which you can use to control the extension. You can enable the API by setting the demoTime.api.enabled
setting to true
. When enabled, the API will run on the port defined in the demoTime.api.port
setting.
API URL: http://localhost:3710/api/next
API endpoints
/api/next
This endpoint will execute the next step in the demo.
- Method:
GET
- Query parameters:
bringToFront
: Bring the Visual Studio Code window to the front. Default is false
.
/api/runById
This endpoint will execute a specific step by its ID in your demo.
You can call this endpoint via a GET
or POST
request.
GET request
- Method:
GET
- Query parameters:
id
: The ID of the step you want to
bringToFront
: Bring the Visual Studio Code window to the front. Default is false
.
POST request
Tips and tricks
Adding notes
You are also able to add notes to your demos. These notes can be used to provide additional information for yourself or others who will be executing the demo.
The notes should be created as a markdown file in the .demo
folder. Here is an example of how you can add notes to your demo:
{
"title": "<title>",
"description": "<description>",
"steps": [...],
"notes": {
"path": "<relative path in the .demo folder>",
"showOnTrigger": "<show notes on trigger (optional) - default is false>"
}
}
Highlighting code
By default, the extension highlights the code in a box with a red border. You can customize how you want to highlight the code with the highlight settings.
![Default highlighting](https://raw.githubusercontent.com/estruyf/vscode-demo-time/dev/assets/highlight-default.png)
Customizing the highlight
Here is an example where the highlight border and background color are customized. Besides these color changes, the text which is not highlighted is blurred and its opacity is reduced to have a better focus on the highlighted code.
{
"demoTime.highlightBorderColor": "transparent",
"demoTime.highlightBackground": "rgba(19, 142, 151, 0.2)",
"demoTime.highlightOpacity": 0.5,
"demoTime.highlightBlur": 2
}
![Customized highlighting](https://raw.githubusercontent.com/estruyf/vscode-demo-time/dev/assets/highlight-custom.png)
Working with variables
You can define variables in a variables.json
file in the .demo
folder. You can reference these variables in your demo steps by using curly braces {variable_name}
.
The extension has also built-in support for a couple of predefined variables:
{DT_INPUT}
: The extension will ask you to provide a value for this variable when the demo gets executed.
{DT_CLIPBOARD}
: The value in your clipboard will be used for this variable.
{SCRIPT_<key>}
: The output of the script which you executed via the executeScript
action, will be used for this variable.
{STATE_<key>}
: The value of the state key which you set via the setState
action, will be used for this variable.
Example variables file
{
"SLIDES_URL": "http://localhost:3030"
}
Example demo step
{
"action": "executeVSCodeCommand",
"command": "simpleBrowser.show",
"args": "{SLIDES_URL}"
}
Positioning your text/code
For the positioning of the text to insert, there are two options:
- Use the
position
property to specify the location where the action should be performed. With this property, you can specify the line number, character position, or a range of lines and characters.
- Use the
startPlaceholder
and endPlaceholder
properties to specify the text to search for in the file to determine the location where the action should be performed.
Line position or range
For the position
property, you can use the following values:
number
: The line number
number:number
: The start and end line number
number,number
: The start line and character
number,number:number,number
: The start line and character and the end line and character
- The
start
and end
keywords can also be used instead of the line numbers
start
will be replaced by the first line number
end
will be replaced by the last line number
Examples:
"position": "10" // Line 10
"position": "10:20" // Lines 10 to 20
"position": "10,5" // Start line 10, character 5
"position": "10,5:20,10" // Start line 10, character 5 to end line 20, character 10
Placeholder position
For the startPlaceholder
and endPlaceholder
properties, you specify the text to search for in the file.
Examples:
"startPlaceholder": "// Start of demo1"
"endPlaceholder": "// End of demo1"
The text will be replaced from the start of the startPlaceholder
to the end of the endPlaceholder
.
In the file, the placeholders should be defined like this:
// Start of demo1
const ext = "Demo Time";
// End of demo1
Adding content to a file
When you want to insert content to a file, you can use the content
or contentPath
properties in the demo step.
Property |
Description |
content |
This property allows you to add the content directly in the JSON file, but this can make your JSON file quite big and it can be hard to read. |
contentPath |
This property allows you to reference a file in the .demo folder. This way you can keep your JSON file clean and add the content in separate files. Important: the path is relative to the .demo folder. |
Presentation view
When you use two screens during a presentation, you can use the detachable presenter view which you can move to another screen. This way you can keep an eye on the next steps while presenting without showing it to your audience.
Follow these steps to use the presenter view:
- Run the
Demo Time: Show presenter view
command to open the presenter view.
- The presenter view will open in detached mode. If that is not the case, you can drag tab out of the Visual Studio Code window.
- Once detached, you can move it to another screen.
![Presenter view](https://raw.githubusercontent.com/estruyf/vscode-demo-time/dev/assets/presenter-view.png)
Example demo file
Here is an example demo:
{
"$schema": "https://demotime.elio.dev/demo-time.schema.json",
"title": "Sample demo",
"description": "This is a sample demo configuration to show the capabilities of the extension.",
"demos": [
{
"title": "Step 1",
"description": "This is step 1",
"steps": [
{
"action": "create",
"path": "sample.json",
"content": "{\n \"firstName\": \"Elio\",\n \"lastName\": \"Struyf\"\n}"
},
{
"action": "open",
"path": "sample.json"
},
{
"action": "highlight",
"path": "sample.json",
"position": "2:3"
}
]
},
{
"title": "Step 2",
"description": "This is step 2",
"steps": [
{
"action": "snippet",
"contentPath": "./snippets/insert_and_highlight.json",
"args": {
"MAIN_FILE": "sample.json",
"CONTENT_PATH": "content.txt",
"CONTENT_POSITION": "3",
"HIGHLIGHT_POSITION": "4"
}
}
]
}
]
}
You can also explore a comprehensive example in the following GitHub Repositories:
Support
If you enjoy my work and find them useful, consider sponsor me and the ecosystem to help Open Source sustainable. Thank you!