npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cthulhu-rlyeh

v5.3.6

Published

DOM manipulation based on cthulhu node architecture

Readme

Doom: Virtual DOM Implementation for Cthulhu Architecture

Overview

Cthulhu Architecture

Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Cthulhu is a transcendental intergalactic Design Pattern that provides an elegant way to write node architecture-based applications. It's relies on a self structure building principle that allows deep node structures to be recursively composed as objects.

Core Principles:

  • Node-based Architecture: Applications are built as interconnected nodes
  • Clean Separation: Clear boundaries between different concerns
  • Modular Design: Components that can be easily composed and reused
  • State Management: Each node manages its own state and lifecycle
  • Deep Node Nesting: Allows for unlimited nesting depth

Doom: Cthulhu's Virtual DOM Implementation

Doom (Document Object Oriented Model) is a sophisticated Virtual DOM implementation that extends the Cthulhu architecture to provide efficient DOM manipulation for web applications. It allows developers to build rich, interactive web applications using pure JavaScript without traditional HTML templates. Instead of introducing an additional HTML transpilation layer, Cthulhu-Rlyeh allows you to directly manipulate the doom. This approach eliminates the need for an intermediate step of transpiling HTML, resulting in a more streamlined and efficient process.

Why Doom?

  • Pure JavaScript: No HTML files or templates required
  • Performance: Efficient Virtual DOM with smart reconciliation
  • Architecture: Built on Cthulhu Node patterns, allowing independent state management
  • Flexibility: Component-based approach for complex applications

Core Concepts

Virtual DOM Principles

A Virtual DOM that maintains a virtual representation of the actual DOM. This allows for:

  • Efficient Updates: Only changed parts of the DOM are updated
  • Performance Optimization: Minimizes expensive DOM operations
  • Declarative API: Describe what you want, not how to achieve it
  • Cross-browser Compatibility: Abstracts browser differences

Reconciliation Process

Doom uses a sophisticated reconciliation algorithm to efficiently update the DOM:

  1. State Comparison: Compares old and new virtual DOM states
  2. Diff Calculation: Identifies minimal changes needed
  3. Batch Updates: Applies changes in optimal batches
  4. Garbage Collection: Cleans up removed elements automatically

Component Lifecycle

Doom tracks component states throughout their lifecycle:

  • Virgin State: Component has never been built
  • Rendered State: Component is currently in the doom, but never rendered on DOM
  • Deleted State: Component marked for removal
  • Root State: Component serves as a root element

State Management

Doom provides several state management features:

  • Deep Cloning: Preserves state through updates
  • Immutable Updates: Ensures predictable state changes
  • Event Handling: Managed event listeners with cleanup
  • Style Management: Dynamic CSS style updates

API Documentation

Static Methods

Doom.$(tag, properties)

Creates a new Doom instance and builds it as a root element.

const element = await Doom.$('div', {
    content: 'Hello World',
    attributes: { id: 'my-element' },
    styleProps: { color: 'blue' }
});

Parameters:

  • tag (string): HTML tag name
  • properties (object): Element properties

Returns: Promise resolving to Doom instance

Instance Methods

build(tag, update)

Creates or updates a DOM element. This is the core method for DOM construction.

const doom = new Doom({
    content: 'Dynamic content',
    events: {
        click: [handler1, handler2]
    }
});

await doom.build('div');

Parameters:

  • tag (string|null): HTML tag name or null for existing element
  • update (boolean): Whether this is an update operation

Returns: Promise resolving to this Doom instance

renderOn(parent)

Renders the element into a parent DOM element.

const parent = document.getElementById('container');
doom.renderOn(parent);

Parameters:

  • parent (HTMLElement): Parent element to render into

removeFrom(parent)

Removes the element from a parent DOM element.

doom.removeFrom(parent);

Parameters:

  • parent (HTMLElement): Parent element to remove from

delete()

Marks the element for deletion and removes it from the DOM.

doom.delete();

Properties & Getters

root

Indicates if the element is a root element.

doom.root = true; // Mark as root

isRendered

Returns true if the element has been rendered to the DOM.

if (doom.isRendered) {
    console.log('Element is in the DOM');
}

isVirgin

Returns true if the element has never been built.

if (doom.isVirgin) {
    console.log('Element has never been built');
}

isDeleted

Returns true if the element has been marked for deletion.

if (doom.isDeleted) {
    console.log('Element is marked for deletion');
}

Usage Examples

Basic Element Creation

import { Doom } from './doom.js';

// Create a simple div element
const element = await Doom.$('div', {
    content: 'Hello, World!',
    attributes: {
        id: 'greeting',
        className: 'text-center'
    },
    styleProps: {
        color: 'blue',
        fontSize: '24px'
    }
});

// Render to page
element.renderOn(document.body);

Nested Components

const app = await Doom.$('div', {
    header: {
        content: 'My Application',
        styleProps: { fontSize: '32px', fontWeight: 'bold' }
    },
    content: {
        content: 'Welcome to my app!',
        styleProps: { padding: '20px' }
    },
    footer: {
        content: '© 2023 My App',
        styleProps: { textAlign: 'center', color: '#666' }
    }
});

app.renderOn(document.body);

Style Properties (styleProps)

const div = await Doom.$('div', {
    styleProps: {
        color: 'blue',
        fontSize: '16px',
        padding: '10px',
        margin: '5px',
        display: 'flex',
        justifyContent: 'center'
    }
});

Attributes Structure

const range = await Doom.$('input',{
    attributes:{
        type:'number',
        min:0,
        max:100
    }
})

range.renderOn(document.body)

Event Handling

const button = await Doom.$('button', {
    content: 'Click me',
    events: {
        click: [
            (e) => console.log('Button clicked'),
            (e) => alert('Hello from Doom!')
        ]
    },
    styleProps: {
        padding: '10px 20px',
        backgroundColor: '#007bff',
        color: 'white',
        border: 'none',
        borderRadius: '4px'
    }
});

button.renderOn(document.body);

Dynamic Lists

const items = ['Apple', 'Banana', 'Cherry'];

const list = await Doom.$('ul', {
    items: items.map((item, index) => ({
        content: item,
        styleProps: {
            padding: '8px',
            borderBottom: '1px solid #eee'
        }
    }))
});

list.renderOn(document.body);

SVG Support

const svg = await Doom.$('svg', {
    nsuri: 'http://www.w3.org/2000/svg',
    width: 200,
    height: 200,
    circle: {
        cx: 100,
        cy: 100,
        r: 50,
        fill: 'blue'
    }
});

svg.renderOn(document.body);

Advanced Features

AI Comment Support

Doom supports AI comments for debugging and documentation. Helps AI to analyze document structure and provide better insights building or testing components via AI:

const element = await Doom.$('div', {
    ai: 'This is a container element for user interface',
    content: 'Main content area'
});

Style Management

Dynamic style updates with automatic cleanup:

const element = await Doom.$('div', {
    styleProps: { color: 'red' }
});

// Update styles later
element.styleProps = { color: 'blue', fontSize: '16px' };
await element.build();

Event Management

Automatic event listener management:

const element = await Doom.$('div', {
    events: {
        click: [handler1, handler2],
        mouseover: [hoverHandler]
    }
});

// Events are automatically cleaned up when element is deleted
element.delete();

Best Practices

Component Composition

Build complex UIs by composing smaller components:

// Create reusable components
const Button = (text, onClick) => Doom.$('button', {
    content: text,
    events: { click: [onClick] }
});

const Card = (title, content) => Doom.$(
    naming(Card), 
    {
        attributes:{
            class:'card'
        },
        header: { content: title },
        body: { content: content }
    });

// Compose them together
const app = await Doom.$('div', {
    button: await Button('Click Me', handleClick),
    card: await Card('Title', 'Content')
});

//Or compose them asynchornous
const [button,card] = await Promise.all([
    Button('Click Me',handleClick),
    Card('Title','Content')
])

const app = await Doom$('div',{
    button,
    card
})

State Management

Use Doom's state tracking for predictable updates and compose complex beaviour components:

class Counter {
    constructor() {
        this.count = 0;
        this.element = null;
    }

    async create() {
        this.element = await Doom.$('div', {
            content: `Count: ${this.count}`,
            events: {
                click: [() => this.increment()]
            }
        });
        return this.element;
    }

    async increment() {
        this.count++;
        this.element.content = `Count: ${this.count}`;
        await this.element.build();
    }
}

Performance Considerations

  • Batch Updates: Group multiple changes together
  • Avoid Deep Nesting: Keep component hierarchies reasonable
  • Use Virtual DOM: Let Doom handle DOM updates efficiently
  • Clean Up Events: Always remove event listeners when done

Integration

With Existing Projects

Doom can be integrated into existing projects:

// Import Doom
import { Doom } from 'cthulhu-rlyeh';

// Use alongside existing code
const existingElement = document.getElementById('existing');
const doomElement = await Doom.$('div', { content: 'New content' });
doomElement.renderOn(existingElement);

Migration from Traditional DOM

Migrate from traditional DOM manipulation:

// Before: Direct DOM manipulation
const element = document.createElement('div');
element.innerHTML = 'Content';
element.style.color = 'red';
document.body.appendChild(element);

// After: Doom approach
const element = await Doom.$('div', {
    content: 'Content',
    styleProps: { color: 'red' }
});
element.renderOn(document.body);

Testing Strategies

// Unit testing with Doom
describe('Doom Component', () => {
    it('should create element with correct content', async () => {
        const element = await Doom.$('div', { content: 'Test' });
        expect(element.content).toBe('Test');
    });

    it('should handle events correctly', async () => {
        let clicked = false;
        const element = await Doom.$('button', {
            events: { click: [() => clicked = true] }
        });
        
        element.#self.click();
        expect(clicked).toBe(true);
    });
});

use.js Module

The use.js module provides utility functions for managing Doom instances with enhanced lifecycle and reactive capabilities.

Key Benefits

  • Chainable API for better code readability
  • Automatic cleanup of DOM elements
  • Integration with reactive state management
  • Simplified component operations

Core Components

  • NodeWrapper: Enhanced wrapper for Doom instances
  • use(): Factory function for creating wrappers

NodeWrapper Class

Wraps Doom instances to provide enhanced management capabilities.

Constructor

new NodeWrapper(node)

Creates a wrapper around a Doom instance.

Methods

clean(child)

Removes a child node from the wrapped node.

use(component)
    .clean(child => child.eventListeners);
cleanMany(children)

Removes multiple child nodes.

use(component)
    .cleanMany(children => children.subComponents);
update(change)

Applies updates to the wrapped node.

use(component)
    .update(n => n.content = 'New content');
conciliate()

Synchronizes with the reactive system.

use(component)
    .conciliate();

Usage Examples

Basic Component Management

import { use } from './use.js';

// Create and manage a component
const component = await Doom.$('div', { content: 'Hello' });
use(component)
    .update(n => n.content = 'Updated')
    .conciliate();

Event Cleanup

// Clean up event listeners
use(component)
    .clean(child => child.clickListeners)
    .conciliate();

Batch Operations

// Multiple operations in sequence
use(component)
    .cleanMany(children => children.allChildren)
    .update(n => n.styleProps.color = 'blue')
    .conciliate();

Quick Reference

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | clean() | child (function) | NodeWrapper | Removes a child node | | cleanMany() | children (function) | NodeWrapper | Removes multiple child nodes | | update() | change (function) | NodeWrapper | Applies updates | | conciliate() | - | Promise | Syncs with reactive system |

Factory Function

use(node)

Creates a new NodeWrapper instance for the given Doom node.

Router System

The router.js and router-slot.js modules provide a complete client-side routing solution for single-page applications (SPAs) built with Cthulhu-Rlyeh.

Router Class

The Router class handles URL-based routing with support for dynamic parameters, query strings, and browser history management.

Static App Method

Router.App({
    app: () => {},
    service: {}
});

Parameters:

  • app: Main application component function
  • service: Service object for dependency injection

Example:

Router.App({
    app: (service) => {
        return Doom.$('div', {
            content: 'Welcome to the app!',
            styleProps: { padding: '20px' }
        });
    },
    service: {
        apiEndpoint: 'https://api.example.com'
    }
});

Constructor

new Router(routes, service)

Parameters:

  • routes: Object mapping URL patterns to route handlers
  • service: Service object for dependency injection

Example:

const router = new Router({
    '/': (service) => homePage(service),
    '/users/:id': (service) => userProfile(service),
    '/about': (service) => aboutPage(service)
}, {
    apiEndpoint: 'https://api.example.com'
});

Route Matching

The router supports dynamic URL parameters and query strings:

// Dynamic parameters
const router = new Router({
    '/user/:id': (service) => {
        const { params } = service;
        return Doom.$('div', {
            content: `User ID: ${params.id}`
        });
    },
    '/product/:category/:id': (service) => {
        const { params } = service;
        return Doom.$('div', {
            content: `Category: ${params.category}, ID: ${params.id}`
        });
    }
});

Query String Handling

// Query parameters
const router = new Router({
    '/search': (service) => {
        const { query } = service;
        return Doom.$('div', {
            content: `Search for: ${query.q || 'everything'}`
        });
    }
});

Router Slot System

The router-slot.js module provides a slot mechanism for rendering routed content within components.

Basic Usage

import { routerSlot } from './router-slot.js';

const layout = await Doom.$('div', {
    header: {
        content: 'My Application',
        styleProps: { padding: '10px', backgroundColor: '#f0f0f0' }
    },
    main: {
        // This will be replaced by routed content
        content: 'Loading...'
    }
});

// Update the main content with routed component
routerSlot(layout, await currentRouteComponent());

Integration with Router

// In your main application
Router.App({
    app: (service) => {
        const layout = Doom.$('div', {
            header: {
                content: 'My App',
                styleProps: { padding: '10px', backgroundColor: '#333', color: 'white' }
            },
            main: {
                content: 'Loading...'
            }
        });

        // Handle route changes
        const handleRoute = async (route) => {
            const component = await route(service);
            routerSlot(layout, component);
        };

        return layout;
    }
});

Advanced Routing Features

404 Handling

The router automatically provides a 404 page for unmatched routes:

// Custom 404 page
const router = new Router({
    '/': (service) => homePage(service),
    // ... other routes
}, service);

// When no route matches, a default 404 page is shown

History Management

The router uses the browser's history API for navigation:

// Navigation is handled automatically
// Browser back/forward buttons work correctly
// URLs are updated without page reloads

Route Parameters

// Complex parameter handling
const router = new Router({
    '/user/:userId/post/:postId': (service) => {
        const { params, query } = service;
        
        return Doom.$('div', {
            content: `
                User: ${params.userId}
                Post: ${params.postId}
                Comments: ${query.comments || 'all'}
            `
        });
    }
});

Best Practices

Route Organization

// Organize routes by feature
const userRoutes = {
    '/user': (service) => userList(service),
    '/user/:id': (service) => userProfile(service),
    '/user/:id/edit': (service) => userEdit(service)
};

const productRoutes = {
    '/product': (service) => productList(service),
    '/product/:id': (service) => productDetail(service)
};

const router = new Router({
    ...userRoutes,
    ...productRoutes
}, service);

Service Injection

// Use service for shared dependencies
const router = new Router(routes, {
    api: new ApiService(),
    auth: new AuthService(),
    config: {
        theme: 'dark',
        language: 'en'
    }
});

Error Handling

// Handle route errors gracefully
const router = new Router({
    '/': (service) => {
        try {
            return homePage(service);
        } catch (error) {
            return Doom.$('div', {
                content: 'An error occurred',
                styleProps: { color: 'red' }
            });
        }
    }
});

Integration Examples

Complete SPA Example

// main.js
import { Router } from './router.js';
import { routerSlot } from './router-slot.js';

// Define routes
const routes = {
    '/': (service) => homePage(service),
    '/about': (service) => aboutPage(service),
    '/contact': (service) => contactPage(service)
};

// Create layout
const createLayout = () => {
    return Doom.$('div', {
        className: 'app',
        header: {
            content: 'My SPA App',
            styleProps: { padding: '10px', backgroundColor: '#333', color: 'white' }
        },
        navigation: {
            ul: {
                li: [
                    { content: 'Home', events: { click: () => navigate('/') } },
                    { content: 'About', events: { click: () => navigate('/about') } },
                    { content: 'Contact', events: { click: () => navigate('/contact') } }
                ]
            }
        },
        main: {
            content: 'Loading...'
        }
    });
};

// Initialize app
Router.App({
    app: (service) => {
        const layout = createLayout();
        
        // Handle navigation
        const navigate = (path) => {
            const component = routes[path](service);
            routerSlot(layout, component);
        };
        
        return layout;
    },
    service: {
        apiEndpoint: 'https://api.example.com'
    }
});

This routing system provides a complete solution for building single-page applications with clean URL structures, dynamic content loading, and efficient component management within the Cthulhu-Rlyeh architecture.