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

@kiliannnnn/lushland

v0.1.0

Published

A package to use windows elements inside a website

Readme

Lushland - Developer Documentation

A web-based window management system built with Web Components. This guide covers using HTML tags, configuring templates and features, and extending the system.

Quick Start

Basic Setup (Auto-initialization)

<lushland-house contain="true" mode="free">
    <lushland-window template="small"></lushland-window>
</lushland-house>
<lushland-manager orientation="horizontal" position="bot-right"></lushland-manager>
<lushland-menu orientation="vertical"></lushland-menu>

<script type="module" src="index.js"></script>

Custom Configuration

Lushland supports customization through configuration files and inline options.

Option 1: Load Config from JSON File

Create a lushland-config.json:

{
  "CONFIG": {
    "defaultWidth": 300,
    "defaultHeight": 250,
    "snapDistance": 15,
    "templates": {
      "custom": {
        "title": "Custom Size",
        "height": 500,
        "width": 800
      }
    }
  },
  "THEMES": ["dark", "light", "cyberpunk", "custom"]
}

Then initialize in your HTML:

<script type="module">
  import { initLushland } from './index.js';
  
  await initLushland({
    configFile: './lushland-config.json',
    cssFile: './lushland-theme.css'  // Optional custom CSS
  });
</script>

<lushland-house contain="true">
    <lushland-window template="small"></lushland-window>
</lushland-house>
<lushland-manager></lushland-manager>
<lushland-menu></lushland-menu>

Option 2: Inline Configuration Object

<script type="module">
  import { initLushland } from './index.js';
  
  await initLushland({
    config: {
      CONFIG: {
        defaultWidth: 400,
        defaultHeight: 300,
        templates: {
          large: {
            title: 'Extra Large',
            height: 600,
            width: 1000
          }
        }
      }
    }
  });
</script>

<lushland-house></lushland-house>
<lushland-manager></lushland-manager>
</lushland-menu>

Option 3: Config File + Custom CSS

<script type="module">
  import { initLushland } from './index.js';
  
  await initLushland({
    configFile: './custom-config.json',
    cssFile: './custom-theme.css'  // Custom CSS variables override defaults
  });
</script>

Create custom-theme.css:

/* Your custom CSS variables override Lushland defaults */
:root {
  --ll-color-bg-primary: #1a1a1a;
  --ll-color-accent-primary: #00ff00;
  --ll-spacing-md: 15px;
}

Contents

HTML Tags

<lushland-house>

Main container for windows. Creates draggable, resizable window instances.

Attributes: None required

Example:

<lushland-house id="app"></lushland-house>

JavaScript Access:

const house = document.getElementById('app');
const windowElement = house.children[0]; // Access first window

<lushland-manager>

Control bar for adding windows, toggling themes, and managing the application.

Attributes: None

Features:

  • + button: Add new window (opens feature menu)
  • Theme toggle button: Cycles through dark → light → cyberpunk
  • Displays current application state

Example:

<lushland-manager id="manager"></lushland-manager>

<lushland-menu>

Displays list of open windows. Click window names to focus, click X to close.

Attributes: None

Auto-scales height based on open windows (0 to 30vh)

Example:

<lushland-menu id="menu"></lushland-menu>

<lushland-window>

Individual window element (created programmatically, not in HTML).

Attributes:

  • x - Window X position (pixels)
  • y - Window Y position (pixels)
  • width - Window width (pixels)
  • height - Window height (pixels)
  • title - Window title
  • feature - Feature name to load (e.g., 'notepad', 'calculator')
  • z-index - Stacking order

Example (created via JavaScript):

const window = document.createElement('lushland-window');
window.setAttribute('x', '100');
window.setAttribute('y', '100');
window.setAttribute('width', '400');
window.setAttribute('height', '300');
window.setAttribute('title', 'My Window');
window.setAttribute('feature', 'notepad');
document.getElementById('app').appendChild(window);

Mouse Interactions:

  • Drag by header to move
  • Drag bottom-right corner to resize
  • Click to focus
  • F button: Change feature
  • S button: Snap to grid
  • X button: Close window

feature-menu

Menu for selecting which feature to load in a window. Created automatically.

Example:

// Created automatically when F button is clicked

Configuration

Using the initLushland API

The recommended way to customize Lushland is through the initLushland() function:

import { initLushland } from './index.js';

await initLushland({
  configFile: './my-config.json',    // Optional: path to JSON config
  config: { /* inline config */ },   // Optional: inline configuration object
  cssFile: './my-theme.css'          // Optional: custom CSS variables
});

Configuration Priority (lowest to highest):

  1. Lushland defaults
  2. configFile settings (if provided)
  3. config object settings (if provided)
  4. User CSS variables (highest priority for styling)

CONFIG Object Properties

All settings in the CONFIG object are customizable:

{
  zIndex: { focused: 100, default: 1 },
  snapDistance: 20,                    // Grid snap size in pixels
  gridDefaults: { size: 20 },         // Default grid size
  defaultTitle: 'Window',
  defaultHeight: 200,
  defaultWidth: 200,
  defaultFeature: 'notepad',
  buttons: {
    feature: 'F',                      // Button to change feature
    snap: 'S',                         // Button to snap to grid
    close: 'X'                         // Button to close window
  },
  templates: {
    small: { title: 'Small', height: 150, width: 200 },
    medium: { title: 'Medium', height: 300, width: 400 },
    large: { title: 'Large', height: 450, width: 600 }
  },
  manager: {
    defaultPosition: 'top-left',
    defaultOrientation: 'vertical'
  },
  menu: {
    defaultPosition: 'bot-left',
    defaultOrientation: 'vertical',
    defaultWidth: '200px',
    defaultHeight: '50px'
  }
}

Import and Use Exports

If you need programmatic access to configuration or managers:

import { 
  initLushland,
  CONFIG, 
  FEATURES, 
  CALCULATOR_CONFIG,
  THEMES,
  templateManager,
  featureRegistry,
  windowsManager
} from './index.js';

await initLushland();

// Access or modify config after initialization
console.log(CONFIG.defaultWidth);
CONFIG.defaultWidth = 500;

// Register custom features
featureRegistry.register('mytool', (container) => {
  container.innerHTML = '<div>My Tool</div>';
});

Legacy Approach (Direct Import)

For backward compatibility, you can still import directly from config.js:

import { CONFIG, FEATURES, CALCULATOR_CONFIG, MANAGER_BUTTONS, THEMES } from './config.js';

However, this won't merge with custom configurations. Use initLushland() for customization support.

Adding Templates

Add window size templates in CONFIG.templates:

CONFIG.templates = {
  custom: {
    title: 'Custom Size',
    height: 500,
    width: 800
  }
}

Create a window from a template:

const template = CONFIG.templates.large;
const window = document.createElement('lushland-window');
window.setAttribute('width', template.width);
window.setAttribute('height', template.height);
window.setAttribute('title', template.title);
window.setAttribute('feature', 'notepad');
document.getElementById('app').appendChild(window);

Adding Features

Features are renderers that populate window content.

1. Define Feature in Config

Add to your lushland-config.json:

{
  "FEATURES": {
    "mynotes": {
      "label": "My Notes",
      "icon": {
        "viewBox": "0 0 24 24",
        "paths": [
          { "d": "M4 4H20V20H4Z", "stroke": "white", "stroke-width": "2" }
        ]
      }
    }
  }
}

2. Register Feature Renderer

After initializing Lushland:

import { initLushland, featureRegistry } from './index.js';

await initLushland({
  configFile: './lushland-config.json'
});

// Register the renderer
featureRegistry.register('mynotes', (container) => {
  const content = document.createElement('div');
  content.innerHTML = '<h2>My Notes</h2><textarea></textarea>';
  content.style.padding = 'var(--ll-spacing-md)';
  container.appendChild(content);
});

3. Use in Window

const window = document.createElement('lushland-window');
window.setAttribute('feature', 'mynotes');
document.getElementById('app').appendChild(window);

Alternative: Global Feature Registration

Register features globally before initialization:

window.addEventListener('DOMContentLoaded', () => {
  window.lushlandRegisterFeature('mynotes', (container) => {
    // Your feature code
  });
});

Markdown Support

The Notepad feature includes Obsidian-style markdown.

Supported Elements

| Syntax | Output | |--------|--------| | # Heading 1 | Large heading | | ## Heading 2 | Medium heading | | ### Heading 3 | Small heading | | #### Heading 4 | Small heading | | ##### Heading 5 | Smaller heading | | ###### Heading 6 | Smallest heading | | **bold** or __bold__ | Bold text | | *italic* or _italic_ | Italic text | | ***bold italic*** | Bold + italic | | ~~strikethrough~~ | Crossed out text | | ==highlighted== | Yellow highlight | | `code` | Inline code | | ```language\ncode``` | Code block | | [text](url) | Link (opens in new tab) | | ![alt](url) | Image (responsive) | | [[Page]] | Wiki link to page | | [[Page\|Display]] | Wiki link with custom text | | - item | Unordered list | | 1. item | Ordered list | | - [ ] task | Unchecked task | | - [x] task | Checked task | | > quote | Blockquote | | --- or *** | Horizontal rule | | %%comment%% | Hidden comment |

Toggle Preview

Click the 👁️ button (bottom-left) to toggle between edit and preview modes. The button changes to ✏️ in preview mode.

Example Files

Lushland includes example configuration and theme files to help you get started:

lushland-config.example.json

A complete configuration template showing all customizable options:

cp lushland-config.example.json my-config.json
# Then edit my-config.json with your custom values

Use it:

await initLushland({
  configFile: './my-config.json'
});

lushland-theme.example.css

A template for customizing CSS variables:

cp lushland-theme.example.css my-theme.css
# Then edit my-theme.css to override variables

Use it:

await initLushland({
  cssFile: './my-theme.css'
});

Combining Both

await initLushland({
  configFile: './my-config.json',
  cssFile: './my-theme.css'
});

Themes

Three built-in themes: dark, light, cyberpunk.

Switching Themes

Set theme programmatically:

document.documentElement.setAttribute('data-theme', 'light');
// or remove attribute for default dark theme
document.documentElement.removeAttribute('data-theme');

The Manager component has a built-in theme toggle button that cycles through available themes.

Custom Themes

Method 1: CSS Variables File (Recommended)

Create my-custom-theme.css:

:root {
  /* Override only the variables you want to customize */
  --ll-color-bg-primary: #0a0a0a;
  --ll-color-accent-primary: #ff00ff;
  --ll-spacing-md: 12px;
  /* Other variables use defaults */
}

/* Theme-specific overrides */
html[data-theme="dark"] {
  --ll-color-bg-primary: #000000;
}

html[data-theme="myTheme"] {
  --ll-color-bg-primary: #1a1a1a;
  --ll-color-text-primary: #00ff00;
  --ll-color-accent-primary: #00ff00;
}

Then load it:

await initLushland({
  cssFile: './my-custom-theme.css'
});

Method 2: Update THEMES Array in Config

Add theme names to your config:

{
  "THEMES": ["dark", "light", "cyberpunk", "myTheme", "highContrast"]
}

Then define the styles in your CSS file.

Available CSS Variables

Color Variables (all use --ll- prefix):

--ll-color-bg-primary, --ll-color-bg-secondary, --ll-color-bg-tertiary, --ll-color-bg-quaternary, --ll-color-bg-hover
--ll-color-text-primary, --ll-color-text-secondary, --ll-color-text-muted
--ll-color-border-primary, --ll-color-border-secondary
--ll-color-accent-primary, --ll-color-accent-info, --ll-color-accent-danger, --ll-color-accent-success

Spacing: --ll-spacing-xs, --ll-spacing-sm, --ll-spacing-md, --ll-spacing-lg

Other: --ll-radius-sm, --ll-radius-md, --ll-radius-circle, --ll-shadow-sm, --ll-shadow-md, --ll-shadow-focus, --ll-transition-default

All variables are namespaced with --ll- to prevent conflicts with other libraries.

Quick Tips

Initialization

Auto-initialize (backward compatible):

<script type="module" src="index.js"></script>

Initialize with custom config:

import { initLushland } from './index.js';

await initLushland({
  configFile: './my-config.json',
  cssFile: './my-theme.css'
});

Initialize with inline config:

await initLushland({
  config: {
    CONFIG: {
      defaultWidth: 500,
      defaultHeight: 400
    }
  }
});

Window Management

Programmatically add a window:

import { windowsManager } from './index.js';

const w = document.createElement('lushland-window');
w.setAttribute('x', '50');
w.setAttribute('y', '50');
w.setAttribute('title', 'My Window');
w.setAttribute('feature', 'notepad');
document.getElementById('app').appendChild(w);
windowsManager.addWindow(w.id, w);

Get all open windows:

import { windowsManager } from './index.js';

const allWindows = windowsManager.getAllWindows();
Object.entries(allWindows).forEach(([id, window]) => {
  console.log(id, window.getAttribute('title'));
});

Close all windows:

document.getElementById('app').innerHTML = '';

Feature Registration

Register a custom feature:

import { initLushland, featureRegistry } from './index.js';

await initLushland();

featureRegistry.register('custom', (container) => {
  container.innerHTML = '<h1>Custom Feature</h1>';
});

Use the registered feature:

const w = document.createElement('lushland-window');
w.setAttribute('feature', 'custom');
document.getElementById('app').appendChild(w);

Theme Management

Switch theme programmatically:

document.documentElement.setAttribute('data-theme', 'light');

Get available themes:

import { THEMES } from './index.js';

console.log(THEMES); // ['dark', 'light', 'cyberpunk']

Advanced Config Access

Access configuration after initialization:

import { initLushland, CONFIG, templateManager } from './index.js';

await initLushland();

// Modify config at runtime
CONFIG.defaultWidth = 600;

// Access template manager
const templates = templateManager.getAllTemplates();

Listen for window manager updates:

document.addEventListener('windowsManagerUpdate', (event) => {
  console.log('Windows updated:', event.detail);
});

Clear localStorage theme:

localStorage.removeItem('lushland-theme');

License

© 2025 Lushland. All rights reserved.