This document explains how to create self-documenting demos that generate markdown documentation with screenshots.
The demo documentation system allows you to annotate Java demo files with special markers that are parsed to generate markdown documentation automatically. Screenshots are captured at key steps during demo execution.
Since demos typically use SciJava Commands (the same commands accessible via the Fiji menu), the generated documentation includes:
- Groovy code showing how to script each step
- GUI instructions showing the menu path and parameters for interactive use
- Annotate your demo with
@doc-stepand@doc-commandmarkers in comments - Add screenshot calls using
DemoHelper.shot("prefix_stepname") - Run the demo to capture screenshots to
documentation/resources/ - Run the generator to produce markdown in
documentation/demos/
Use structured comments to mark documentation steps:
// @doc-step: Title of the step
// Description of what this step does. Can span
// multiple lines until the next @doc marker or code.
// Your code for this step...
DemoHelper.shot("DemoName_01_stepname"); // Capture screenshotWhen a step uses a SciJava Command, add the @doc-command marker to include GUI and Groovy equivalents:
// @doc-step: Open the LLS7 Dataset
// Load the downloaded CZI file using the LLS7 opener command.
// This performs live deskewing of the lattice light sheet data.
// @doc-command: ch.epfl.biop.scijava.command.spimdata.LLS7OpenDatasetCommand
ij.command().run(LLS7OpenDatasetCommand.class, true,
"czi_file", fileCZI,
"legacy_xy_mode", false).get();
DemoHelper.shot("DemoLabkit_02_dataset_loaded");The generator will automatically:
- Extract the menu path from the command's
@Pluginannotation - List the command parameters with their descriptions
- Generate equivalent Groovy scripting code
For steps that require user interaction (like drawing annotations, training classifiers, etc.), use @doc-manual:
// @doc-step: Train a Classifier
// Use Labkit's interactive tools to train a pixel classifier.
// @doc-manual: Perform the following steps in Labkit:
// 1. Select the "background" label in the Labels panel
// 2. Use the brush tool to draw scribbles on background regions
// 3. Select the "foreground" label
// 4. Draw scribbles on the cells/structures you want to segment
// 5. Click "Train Classifier" to see the segmentation result
DemoHelper.pauseForUserAction("DemoLabkit_03_trained",
"Please train a classifier in Labkit:\n\n" +
"1. Select the 'background' label...\n" +
"...");The pauseForUserAction() method:
- Prints instructions to the console
- Waits for the user to press Enter
- Automatically captures screenshots after the user action
@doc-step:must be at the start of a comment line (after//)- The text after
:becomes the step title - Subsequent comment lines (until code or another marker) become the description
@doc-command:specifies the fully qualified class name of the command@doc-manual:marks a step as requiring manual user action; subsequent lines become the instruction list- Step descriptions support multiple lines
When a step includes @doc-command, the generator produces documentation like this:
Load the downloaded CZI file using the LLS7 opener command. This performs live deskewing of the lattice light sheet data.
Menu: Plugins > BigDataViewer-Playground > XML Dataset > Create BDV Dataset [Zeiss LLS7]
| Parameter | Description |
|---|---|
| CZI LLS7 File | The CZI file from a Zeiss LLS7 acquisition to open |
| Use Legacy XY Mode | When checked, uses legacy XY orientation for compatibility with older datasets |
#@ CommandService cmd
cmd.run("ch.epfl.biop.scijava.command.spimdata.LLS7OpenDatasetCommand", true,
"czi_file", new File("/path/to/your/file.czi"),
"legacy_xy_mode", false
).get()Use this pattern for screenshot prefixes:
DemoName_XX_stepname
Where:
DemoNamematches the demo class nameXXis a two-digit step number (01, 02, etc.)stepnameis a short identifier for the step
Example:
DemoHelper.shot("DemoLabkitIntegration_02_labkit_open");This creates files like:
documentation/resources/DemoLabkitIntegration_02_labkit_open_ImageJ.png
documentation/resources/DemoLabkitIntegration_02_labkit_open_Labkit.png
Ensure your demo class has a Javadoc comment describing what the demo does:
/**
* Demo showing how to use Labkit with SourceAndConverter from BigDataViewer-Playground.
* <p>
* This demo loads an LLS7 dataset and opens it in Labkit for segmentation.
* </p>
*/
public class DemoLabkitIntegration {Add @doc-step markers before each significant section:
// @doc-step: Initialize ImageJ
// Start the ImageJ application context and show the user interface.
final ImageJ ij = new ImageJ();
ij.ui().showUI();
DemoHelper.shot("DemoName_01_init");After visual changes (windows appearing, data loading), add:
DemoHelper.shot("DemoName_XX_stepname");The shot() method:
- Waits 4 seconds (default) for rendering to complete
- Captures all visible JFrames
- Saves PNGs to
documentation/resources/
Execute your demo's main() method. The demo will run and capture screenshots at each DemoHelper.shot() call.
# From your IDE, run the demo class
# Or use Maven:
mvn exec:java -Dexec.mainClass="DemoLabkitIntegration"After running the demo (and capturing screenshots), run the generator:
mvn exec:java -Dexec.mainClass="DemoDocumentationGenerator" -Dexec.args="DemoLabkitIntegration"Or run DemoDocumentationGenerator.main() from your IDE with the demo class name as an argument.
The generator creates:
documentation/demos/DemoName.md- The markdown documentation
The markdown includes:
- Title and description from class Javadoc
- Each step with its title, description, code snippet, and screenshots
- A prerequisites section
- Links to screenshot images
bigdataviewer-biop-tools/
├── documentation/
│ ├── demos/ # Generated markdown files
│ │ └── DemoLabkitIntegration.md
│ └── resources/ # Screenshots captured during demo runs
│ ├── DemoLabkitIntegration_01_init_ImageJ.png
│ └── DemoLabkitIntegration_02_labkit_open_Labkit.png
├── src/test/java/
│ ├── DemoLabkitIntegration.java # Annotated demo
│ ├── DemoDocumentationGenerator.java # Generator
│ └── DemoHelper.java # Screenshot utility
└── DEMO_DOCUMENTATION.md # This file
/**
* Demo showing feature X with command integration.
*/
public class DemoFeatureX {
public static void main(String[] args) throws Exception {
// @doc-step: Initialize ImageJ
// Create and display the ImageJ application.
// This is required before running any commands.
ImageJ ij = new ImageJ();
ij.ui().showUI();
DemoHelper.shot("DemoFeatureX_01_init");
// @doc-step: Download Sample Data
// Download a sample dataset from Zenodo.
// This step is only needed for the demo - in practice,
// you would use your own data files.
File data = DatasetHelper.getDataset("https://zenodo.org/...");
// @doc-step: Open the Dataset
// Load the dataset using the LLS7 opener command.
// @doc-command: ch.epfl.biop.scijava.command.spimdata.LLS7OpenDatasetCommand
ij.command().run(LLS7OpenDatasetCommand.class, true,
"czi_file", data,
"legacy_xy_mode", false).get();
DemoHelper.shot("DemoFeatureX_02_loaded");
// @doc-step: Display in BigDataViewer
// Show the loaded sources in a BDV window.
// @doc-command: sc.fiji.bdvpg.scijava.command.bdv.BdvSourcesShowCommand
ij.command().run(BdvSourcesShowCommand.class, true,
"sources", sources).get();
DemoHelper.shot("DemoFeatureX_03_displayed");
}
}For the "Open the Dataset" step above, the generator produces:
Using the GUI:
Navigate to Plugins > BigDataViewer-Playground > XML Dataset > Create BDV Dataset [Zeiss LLS7]
and fill in the parameters in the dialog.
Using Groovy Script:
#@ CommandService cmd
cmd.run("ch.epfl.biop.scijava.command.spimdata.LLS7OpenDatasetCommand", true,
"czi_file", new File("/path/to/file.czi"),
"legacy_xy_mode", false
).get()-
Expand tree view: Call this at the beginning of demos to show the full source hierarchy:
DemoHelper.expandTreeView(ij); // Expands to depth 3 by default
-
Wait times: If windows aren't fully rendered, increase wait time:
DemoHelper.shot("prefix", 6000); // Wait 6 seconds
-
Step numbering: Use consistent two-digit numbering (01, 02, ...) to ensure correct ordering.
-
Descriptive names: Use meaningful step names for better screenshot filenames.
-
One visual change per step: Capture after each significant UI change for best documentation.
-
Keep descriptions concise: The description should explain what the step accomplishes, not repeat the code.
-
Semi-interactive demos: Use
pauseForUserAction()for steps requiring manual input:DemoHelper.pauseForUserAction("prefix_03_step", "Instructions for the user...");
- Increase the wait time in
DemoHelper.shot() - Ensure the windows are fully visible on screen
- Verify the prefix pattern matches between code and files
- Check that screenshots are in
documentation/resources/
- Ensure
@doc-step:is spelled correctly with the colon - Check that the marker is at the start of a comment line
