A simple visual block management system for creating interactive, interconnected content
Features β’ Quick Start β’ API β’ Examples β’ Customization β’ License
- Visual Block Management - Create, edit, and organize content blocks with an intuitive interface
- Drag & Drop Positioning - Move blocks freely across the canvas with smooth animations
- Dynamic Resizing - Resize blocks with visual handles (right, bottom, corner)
- Smart Connection System - Create relationships between blocks with intelligent routing
- β Single Direction - One-way connection from source to target
- β Reverse Direction - One-way connection from target to source
- β Bidirectional - Two-way connection between blocks
- Grid Background - 20px grid for precise alignment
- Minimap Navigation - Bird's-eye view with viewport indicator
- Red Circle Endpoints - Visual indicators at connection points
- Hover Effects - Interactive feedback for better UX
- Type Badges - Visual block categorization (Note, Task, Default)
- Import/Export - Full JSON serialization with position and size preservation
- Search Functionality - Real-time content search across all blocks
- Auto-save Positions - Automatic position and size persistence
- Metadata Tracking - Creation and modification timestamps
- Event System - Subscribe to block creation, updates, and deletions
- Zero Dependencies - Pure JavaScript implementation
- Extensible Architecture - Easy to extend with custom block types
- Mobile Support - Touch events for mobile devices
<!-- Include the JavaScript files -->
<script src="blockEngine.js"></script>
<script src="blockRenderer.js"></script>// Initialize the engine
const engine = new BlockEngine();
const renderer = new BlockRenderer(engine, 'container-id');
// Create your first block
const block = engine.createBlock('Hello World!', 'note');
// Link blocks together
const block2 = engine.createBlock('Connected Block');
engine.linkBlocks(block.id, block2.id, 'single');<!DOCTYPE html>
<html>
<head>
<title>Block Engine Example</title>
</head>
<body>
<div id="container-id"></div>
<script src="blockEngine.js"></script>
<script src="blockRenderer.js"></script>
<script>
// Your implementation
</script>
</body>
</html>// Basic block creation
const block = engine.createBlock(content, type, position, size);
// Parameters:
// content: string - The block content
// type: string - Block type ('default', 'note', 'task')
// position: {x, y} - Optional position (auto-positioned if not provided)
// size: {width, height} - Optional size (default: 250x150)// Update block position (with grid snapping)
engine.setBlockPosition(blockId, x, y, snapToGrid = true);
// Update block size (respects minimum dimensions)
engine.setBlockSize(blockId, width, height);// Create different types of connections
engine.linkBlocks(fromId, toId, 'single'); // One-way β
engine.linkBlocks(fromId, toId, 'reverse'); // One-way β
engine.linkBlocks(fromId, toId, 'double'); // Two-way β
// Update existing connection
engine.updateLinkType(fromId, toId, newType);
// Remove connection
engine.unlinkBlocks(fromId, toId);// Get block by ID
const block = engine.getBlock(blockId);
// Search blocks by content
const results = engine.searchBlocks('search term');
// Get connected blocks
const outgoing = engine.getOutgoingLinks(blockId);
const incoming = engine.getIncomingLinks(blockId);
// Get connection information
const linkInfo = engine.getLinkInfo(fromId, toId);
// Returns: { type: 'single'|'reverse'|'double', from: id, to: id }// Export all blocks to JSON
const jsonData = engine.exportToJSON();
// Import blocks from JSON
engine.importFromJSON(jsonData);// Switch between free positioning and grid layout
renderer.setViewMode('free'); // Default: draggable with connections
renderer.setViewMode('grid'); // Auto-layout grid without connections// Select blocks programmatically
renderer.selectBlock(blockId, multiSelect = false);
// Get selected blocks
const selected = renderer.getSelectedBlocks();
// Link selected blocks
renderer.linkSelected('double');// Scroll to specific block
renderer.scrollToBlock(blockId);
// Update connections manually
renderer.updateConnections();
// Refresh minimap
renderer.updateMinimap();// Subscribe to events
engine.on('blockCreated', (block) => {
console.log('New block:', block);
});
engine.on('blockUpdated', (block) => {
console.log('Block updated:', block);
});
engine.on('blocksLinked', ({from, to, linkType}) => {
console.log('Blocks linked:', from.id, '->', to.id);
});
engine.on('blockMoved', (block) => {
console.log('Block moved:', block.position);
});
engine.on('blockResized', (block) => {
console.log('Block resized:', block.size);
});// Create project overview
const overview = engine.createBlock(
'Project: Block Engine\nDeadline: 2025-09-01',
'note',
{x: 400, y: 50}
);
// Create task blocks
const tasks = [
engine.createBlock('Design UI Components', 'task', {x: 200, y: 200}),
engine.createBlock('Implement Core Engine', 'task', {x: 400, y: 200}),
engine.createBlock('Write Documentation', 'task', {x: 600, y: 200})
];
// Link overview to all tasks
tasks.forEach(task => {
engine.linkBlocks(overview.id, task.id, 'single');
});
// Create task dependencies
engine.linkBlocks(tasks[0].id, tasks[1].id, 'single');
engine.linkBlocks(tasks[1].id, tasks[2].id, 'single');// Create concept blocks
const concepts = {
js: engine.createBlock('JavaScript', 'note'),
dom: engine.createBlock('DOM Manipulation', 'note'),
events: engine.createBlock('Event Handling', 'note'),
async: engine.createBlock('Async Programming', 'note')
};
// Create relationships
engine.linkBlocks(concepts.js.id, concepts.dom.id, 'single');
engine.linkBlocks(concepts.js.id, concepts.events.id, 'single');
engine.linkBlocks(concepts.js.id, concepts.async.id, 'single');
engine.linkBlocks(concepts.events.id, concepts.dom.id, 'double');class CustomBlockEngine extends BlockEngine {
createBlock(content, type = 'default', position = null, size = null) {
// Add custom validation
if (type === 'important') {
size = size || {width: 300, height: 200};
}
return super.createBlock(content, type, position, size);
}
}/* Override default styles */
.block {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.block-type {
background: rgba(255, 255, 255, 0.2);
color: white;
}
.link-endpoint {
background: #ffd700; /* Gold endpoints */
}// Add custom metadata to blocks
const block = engine.createBlock('Content');
block.customData = {
priority: 'high',
tags: ['important', 'review'],
assignee: 'pavadik'
};engine.settings = {
gridSize: 20, // Grid snapping size
defaultSpacing: 300, // Auto-position spacing
minBlockWidth: 150, // Minimum block width
minBlockHeight: 100 // Minimum block height
};- Mind Mapping - Visual brainstorming and idea organization
- Project Management - Task dependencies and workflow visualization
- Knowledge Graphs - Concept relationships and learning paths
- System Design - Architecture diagrams and component relationships
- Content Planning - Editorial calendars and content relationships
- Data Modeling - Entity relationships and database schemas
block-engine/
βββ blockEngine.js # Core engine logic
βββ blockRenderer.js # Visual rendering layer
βββ example.html # Usage example
βββ README.md # This file
- Block Engine - Core data management and business logic
- Block Renderer - Visual representation and interaction handling
- Event System - Pub/sub for reactive updates
- Position Manager - Grid snapping and auto-positioning
- Link Manager - Connection routing and type management
Contributions are welcome! Please feel free to submit a Pull Request.
- Maintain zero dependencies
- Follow ES6+ standards
- Ensure mobile compatibility
- Add JSDoc comments
- Update documentation
MIT License - feel free to use this in your projects!
Created with β€οΈ by Paul Dikaloff