| name | vis-network |
| description | Create an educational MicroSim using the vis-network JavaScript library. Each MicroSim is a directory located in the /docs/sims folder. It has a main.html file that can be referenced with an iframe. The main.html file imports the main JavaScript code to run the educational MicroSim. |
Educational MicroSim Creation Skill for Vis-Network
Overview
This skill contains the rules for generating a Educational MicroSim using the vis.network JavaScript library.
MicroSims are lightweight, interactive educational simulations designed for browser-based learning.
MicroSims occupy a unique position at the intersection of
- Simplicity (focused scope, transparent code)
- Accessibility (browser-native, universal embedding)
- AI Generation (standardized patterns, prompt-compatible design).
Purpose
Educational MicroSims transform abstract concepts into visual interactive, manipulable experiences that enable students to learn through exploration and experimentation. Each MicroSim addresses specific learning objectives while maintaining the pedagogical rigor and technical quality necessary for educational deployment.
Default Layout: vis-network-tutorial
The vis-network-tutorial layout is the standard template for all vis-network MicroSims embedded in intelligent textbooks. This layout features:
- Graph on the left - Network visualization occupies the left portion of the canvas
- Controls on the right - Interactive controls, status panels, and legends in the right panel
- Title at top center - Clear identification of the visualization
- Legend in upper left - Color/symbol key for understanding the visualization
- Responsive design - Works across different screen sizes
Reference Implementation: See /docs/sims/three-color-dfs/ for a complete working example.
Development Process
Step 1: Educational Requirements Specification
Before generating code, articulate the educational purpose:
- Subject Area and Topic: What specific concept does this simulation teach?
- Grade Level: Elementary (K-5), Middle School (6-8), High School (9-12), or Undergraduate
- Learning Objectives: What should students understand after using this simulation? (Align with Bloom's Taxonomy: Remember, Understand, Apply, Analyze, Evaluate, Create)
- Duration: Typical engagement time (5-15 minutes recommended)
- Prerequisites: What knowledge must students have before using this?
- Assessment Opportunities: How can educators verify learning?
Step 2: MicroSim Implementation with Vis-Network
Generate a self-contained, interactive vis-network.js simulation following the standardized MicroSim architecture. The program is width responsive.
Folder Structure
Each Vis-Network MicroSim is contained in a folder within the /docs/sims directory. The folder name is $MICROSIM_NAME
/docs/sims/$MICROSIM_NAME
/docs/sims/$MICROSIM_NAME/index.md # Documentation with iframe embed
/docs/sims/$MICROSIM_NAME/main.html # HTML5 file with vis-network CDN link
/docs/sims/$MICROSIM_NAME/style.css # All CSS styles (extracted from HTML)
/docs/sims/$MICROSIM_NAME/$MICROSIM_NAME.js # All vis-network JavaScript
/docs/sims/$MICROSIM_NAME/metadata.json # Dublin core metadata
Step 3: Default Interaction Settings
IMPORTANT: All vis-network MicroSims embedded in textbooks via iframe MUST disable mouse-based zoom and pan, and enable navigation buttons instead.
Required Interaction Options
const options = {
interaction: {
zoomView: false,
dragView: false,
navigationButtons: true
}
};
Rationale
These settings are mandatory for textbook embedding because:
-
Scroll Interference: When a vis-network diagram is embedded in a textbook page via iframe, mouse wheel zoom captures scroll events. This prevents users from scrolling through the textbook content, creating a frustrating user experience.
-
Touch Device Conflicts: On tablets and phones, pinch-to-zoom and drag gestures conflict with page navigation and scrolling.
-
Accessibility: Navigation buttons provide a consistent, discoverable interface for all users, including those using assistive technologies.
-
Predictable Behavior: Students expect scrolling to move through content, not zoom into diagrams.
Exception: Fullscreen Mode
The ONLY exception to this rule is when a diagram is displayed in fullscreen mode (not embedded in an iframe). In fullscreen mode, mouse zoom and pan may be enabled since there is no surrounding content to scroll.
Detecting Iframe vs Fullscreen Context
Use these utility functions to detect the execution context and conditionally enable mouse interactions:
function isInIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
function isFullscreen() {
return !!(document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement);
}
Conditional Interaction Options
Use the environment detection to set appropriate interaction options:
function initializeNetwork() {
const enableMouseInteraction = !isInIframe();
const options = {
layout: { improvedLayout: false },
physics: { enabled: false },
interaction: {
selectConnectedEdges: false,
dragView: enableMouseInteraction,
zoomView: enableMouseInteraction,
navigationButtons: true,
keyboard: {
enabled: true,
bindToWindow: false,
speed: { x: 2, y: 2, zoom: 0.01 }
}
},
};
const container = document.getElementById('network');
network = new vis.Network(container, data, options);
}
Editor Mode with Save Functionality
For MicroSims that need manual node positioning, implement an editor mode using URL parameters:
function isSaveEnabled() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('enable-save') === 'true';
}
function initializeNetwork() {
const saveEnabled = isSaveEnabled();
const options = {
interaction: {
dragNodes: saveEnabled,
dragView: saveEnabled || !isInIframe(),
zoomView: saveEnabled || !isInIframe(),
navigationButtons: true
}
};
const saveControls = document.getElementById('save-controls');
if (saveControls) {
saveControls.style.display = saveEnabled ? 'flex' : 'none';
}
}
Save Node Positions to JSON
When editor mode is enabled, provide functionality to save updated node positions:
function saveNodePositions() {
const positions = network.getPositions();
graphData.nodes.forEach(node => {
if (positions[node.id]) {
node.x = Math.round(positions[node.id].x);
node.y = Math.round(positions[node.id].y);
}
});
graphData.metadata.lastUpdated = new Date().toISOString().split('T')[0];
const jsonString = JSON.stringify(graphData, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.();
a. = url;
a. = ;
..(a);
a.();
..(a);
.(url);
}
Summary: Interaction Mode Matrix
| Context | dragView | zoomView | dragNodes | Use Case |
|---|
| Iframe (default) | false | false | false | Normal textbook embedding |
| Fullscreen/Standalone | true | true | true | User opened main.html directly |
| Editor Mode | true | true | true | Developer positioning nodes |
Step 4: Standard vis-network Options Template
Use this template for all new vis-network MicroSims:
const options = {
layout: {
improvedLayout: false
},
physics: {
enabled: false
},
interaction: {
selectConnectedEdges: false,
zoomView: false,
dragView: false,
navigationButtons: true
},
nodes: {
shape: 'box',
margin: 12,
font: {
size: 16,
face: 'Arial'
},
borderWidth: 3,
shadow: {
enabled: true,
color: 'rgba(0,0,0,0.2)',
size: 5,
x: 2,
y: 2
}
},
edges: {
arrows: {
to: { enabled: true, scaleFactor: 1.2 }
},
width: 2,
smooth: {
type: 'curvedCW',
:
}
}
};
Complete Template Files
main.html Template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$MICROSIM_TITLE</title>
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div id="network"></div>
<div class="title">$MICROSIM_TITLE</div>
<div class="legend">
Label 1 - Description
Label 2 - Description
Step 0 / N
Next Step
Reset
Current Action:
Click "Next Step" to begin.
style.css Template
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: aliceblue;
}
.container {
position: relative;
width: 100%;
height: 100vh;
}
#network {
width: 100%;
height: 100%;
background-color: aliceblue;
}
.title {
position: absolute;
top: 10px;
left: 50%;
: (-);
: ;
: bold;
: black;
: aliceblue;
: ;
}
{
: absolute;
: ;
: ;
: ;
: (, , , );
: ;
: (,,,);
: ;
}
{
: flex;
: center;
: ;
: ;
}
{
: ;
: ;
: ;
: ;
: solid ;
}
{ : ; }
{ : ; }
{ : ; }
{
: absolute;
: ;
: ;
: ;
: flex;
: column;
: ;
: ;
}
{
: (, , , );
: ;
: ;
: (,,,);
}
{
: bold;
: ;
: ;
}
{
: ;
: ;
}
{
: flex;
: ;
: center;
: (, , , );
: ;
: ;
: (,,,);
}
{
: ;
: ;
: ;
}
{
: ;
: ;
: bold;
: none;
: ;
: pointer;
: all ;
}
{
: ;
: white;
}
{
: ;
}
{
: ;
: not-allowed;
}
{
: ;
: white;
}
{
: ;
}
(: ) {
{
: ;
}
{
: ;
}
{
: ;
}
{
: ;
}
{
: ;
}
{
: ;
: ;
}
{
: ;
}
}
JavaScript Template ($MICROSIM_NAME.js)
const colors = {
default: {
background: '#e0e0e0',
border: '#757575',
font: '#333333'
},
active: {
background: '#ffd700',
border: '#ffa000',
font: '#333333'
},
complete: {
background: '#4caf50',
border: '#2e7d32',
font: '#ffffff'
}
};
const nodeData = [
{ id: 1, label: 'Node 1', x: -300, y: -100 },
{ id: 2, label: 'Node 2', x: -100, y: -100 },
{ id: 3, label: 'Node 3', x: -300, y: 100 },
{ : , : , : -, : }
];
edgeData = [
{ : , : },
{ : , : },
{ : , : },
{ : , : }
];
currentStep = ;
nodeColors = {};
steps = [
{ : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : }
];
nodes, edges, network;
() {
(network) {
network.({
: { : -, : },
: ,
:
});
}
}
() {
currentStep = ;
nodeColors = {};
initialNodes = nodeData.( {
nodeColors[node.] = ;
{
: node.,
: node.,
: node.,
: node.,
: {
: colors..,
: colors..
},
: { : colors.., : }
};
});
initialEdges = edgeData.( ({
: index,
: edge.,
: edge.,
: { : },
:
}));
nodes = vis.(initialNodes);
edges = vis.(initialEdges);
options = {
: { : },
: { : },
: {
: ,
: ,
: ,
:
},
: {
: ,
: ,
: { : , : },
: ,
: {
: ,
: ,
: ,
: ,
:
}
},
: {
: { : { : , : } },
: ,
: { : , : }
}
};
container = .();
data = { : nodes, : edges };
network = vis.(container, data, options);
(positionView, );
();
}
() {
nodeColors[nodeId] = colorName;
colorSet = colors[colorName];
nodes.({
: nodeId,
: {
: colorSet.,
: colorSet.
},
: { : colorSet., : }
});
}
() {
stepCounter = .();
statusText = .();
nextBtn = .();
stepCounter. = ;
(currentStep < steps.) {
statusText. = steps[currentStep].;
}
nextBtn. = currentStep >= steps. - ;
}
() {
(currentStep >= steps. - ) ;
currentStep++;
step = steps[currentStep];
(step.) {
:
(step., );
;
:
(step., );
;
}
();
}
() {
();
}
.(, () {
();
.().(, executeStep);
.().(, reset);
.(, positionView);
});
Graph Positioning Guide
When creating a new vis-network MicroSim, proper positioning requires adjusting two areas:
1. Node Positions (nodeData array)
Place nodes on the left side of the canvas using negative x values:
const nodeData = [
{ id: 1, label: 'Node 1', x: -350, y: -150 },
{ id: 2, label: 'Node 2', x: -100, y: -150 },
{ id: 3, label: 'Node 3', x: -350, y: 150 },
{ id: 4, label: 'Node 4', x: -100, y: 150 }
];
Coordinate System:
- Canvas center is
(0, 0)
- Negative x = left side of canvas
- Negative y = top of canvas
- Typical x range for left-side placement:
-400 to -50
- Typical y range:
-200 to +400 depending on number of nodes
2. Camera/View Position (positionView function)
The moveTo() function controls the initial camera position:
network.moveTo({
position: { x: -90, y: 60 },
scale: 1,
animation: false
});
Adjustment Guide:
- x value: Lower = view shifts RIGHT (shows more of left-positioned nodes)
- y value: Higher = view shifts UP (shows more of bottom nodes)
- scale:
1 = default zoom, 0.8 = zoomed out, 1.2 = zoomed in
Common adjustments:
- Graph cut off on left? → Decrease x (e.g.,
-120)
- Graph cut off on bottom? → Increase y (e.g.,
100)
- Graph too small? → Increase scale (e.g.,
1.1)
Testing Positioning
Test your MicroSim locally:
http://127.0.0.1:8000/[repo-name]/sims/[microsim-name]/main.html
Adjust node positions and camera position iteratively until the graph is well-centered on the left with the right panel visible on the right.