Drafty: VSCode Markdown Code Runner with Jupyter-like Features
Drafty lets you run fenced python blocks in Markdown files, track session state across multiple runs, tinker interactive plots, and save / load execution results to/from JSON files.
Install the Extension
- Install from VS Code marketplace by searching for "Drafty Runner"
- Or use the command:
code --install-extension fit-cnice.drafty
Quick Start
Create a fenced codeblock
- Thanks to
fenced codeblocks snippet in VSCode, you can create python code blocks easily

Start a session
Just like Jupyter notebook, you can start a separate kernel for each opened MD file. To do so, simply
- Open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
- Type "Drafty: Start Session"
- Select your preferred Python environment in opened panel
Note: you will need to have IPython installed in your environment, which is default in normal conda env.

Run Your Code by Varying the tail number
When clicking Run , Drafty will
- create a
DRAFTY-ID for the block, which has a 3-digit belly number and a 1-digit tail number.
- You can change the tail number will render different results(snapshots) of the same codeblock.

This is useful when you have tinker-check cycles in your workflow.
Name and rearrange result snapshots
- We provide special directive
#| title: xxxx to name a render snapshot to make it easier to find
- You can rearrange codeblocks and their result snapshots will be shuffled to reflect updated codeblock order

Render Interactive Plot through Directives
Unlike Jupyter notebook, Drafty employs plotly.js to render interactive scatter/curve/surface plots. Through #| directives, user can easily
- create slider or input controls
- specify plot type and "onUpdate" commands (more details in Sec. Special Directives)

Save Your Results
- Click the "Save"/"Save as" button in the results panel to store outputs
- Use "Load Results" to restore previous session states

More examples can be found in test/examples/notes.
Special Directives
We provide special directives(lines starting with #| ) to create interactive plots. Per ChatGPT, 3 syntax rules for writing directives are:
- Start every directive with
#| followed by a keyword (like slider , input , or curve ) and a colon.
- After the colon, list parameters separated by commas—for example, a basic slider is written as
#| slider: param_name, min, max, step .
- To add multiple items in one line, group shared settings in square brackets (e.g.,
[param1, param2] ) or separate different settings with semicolons (e.g., #| slider: param1, 0, 5, 0.1; param2, 5, 15, 0.1 ).
For a detailed explanation, we have implemented the following interactive elements:
- Sliders
- single slider control,
#| slider: param_name, min_val, max_val, step ("step" is optional)
- multiple sliders sharing one range,
#| slider: [param_1, param_2], min_val, max_val, step
- sliders of different ranges,
#| slider: param_1, min, max, step; param_2, min, max, step
- Inputs
- single number input,
#| input: param_name, default_num
- number inputs sharing one default,
#| input: [param_1, param_2], default
- inputs with different defaults,
#| input: param_1, default_1; param_2, default_2
- single dropdown menu,
#| input: param_name, ["opt1","opt2"]
- multiple dropdown menus,
#| input: param_1, ["opt1","opt2"]; param_2, ["opt3", "opt4"]
- Plots
- Dynamic plots(that should be updated when tinkering sliders/inputs)
- single curve plot,
#| curve: y_name=some_func(x,...) ("..." indicates other arguments)
- multiple curves,
#| curve: y1=func_1(x1,...); y2 = func_2(x2,...)
- single scatter/surface plot,
#| scatter/surface: z=some_func(x,y,...)
- multiple scatter groups,
#| scatter: z1=func1(x1,y1,...); z2=func2(x2,y2,...)
- Static plots(that should not be updated, usually served as references)
- single x-y curve:
#| curve: [x_name,y_name]
- multiple x-y curves:
#| curve: [x_1, y_1]; [x_2, y_2]
- single scatter/surface:
#| scatter/surface: [x_1, y_1, z_1]
- multiple scatter groups/surfaces:
#| scatter/surface: [x_1, y_1, z_1]; [x_2, y_2, z_2]
Extension Configurations
drafty.defaultPath : Default path used when saving results JSON with the 'Save' button, default value is pwd.
drafty.removeOrphanedBlocks : Whether remove result blocks from the panel when its ID has no matched belly number in MD doc, default is false.
drafty.savingRule : If set to latest-only , old JSON result files are removed before saving new JSON file. Otherwise keep all saved files(keep-all ).
Contributing
Clone this repo and run npm ci . PR is welcomed.
| |