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

@metapages/metapage

v1.10.0

Published

Connect web pages together

Readme

@metapages/metapage

Build composable, interconnected web applications using iframes and data pipes

npm version

@metapages/metapage is a JavaScript library that lets you create and embed interactive workflows in the browser by connecting independent iframe components together through input/output data pipes.

Quick Links

What is this?

A metapage is a web application made up of connected iframes called metaframes. Each metaframe can:

  • Receive data from other metaframes (inputs)
  • Send data to other metaframes (outputs)
  • Run independently (JavaScript, Docker containers, markdown editors, or any web component)

Think of it like a visual programming environment where each component is a full web application that can communicate with others through simple JSON data pipes.

Installation

npm install @metapages/metapage

Or use directly from CDN:

import {
  renderMetapage,
  Metapage,
  Metaframe,
} from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

Quick Start

Rendering a Metapage

The simplest way to embed a workflow is using renderMetapage:

import { renderMetapage } from "@metapages/metapage";

// Fetch a metapage definition (or define your own JSON)
const response = await fetch(
  "https://metapage.io/m/87ae11673508447e883b598bf7da9c5d/metapage.json",
);
const definition = await response.json();

// Render it
const { setInputs, dispose } = await renderMetapage({
  definition,
  rootDiv: document.getElementById("container"),
});

The renderMetapage function the react-grid-layout layout in metapage.json:

{
  "meta": {
    "layouts": {
      "react-grid-layout": {
        ...
      }
    }
  }
}

Implentation in source code

Creating a Metaframe (Inside an iframe)

If you're building a component to use in a metapage:

import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

const metaframe = new Metaframe();

// Listen for input data from other metaframes
metaframe.onInput("data", (value) => {
  console.log("Received:", value);
  // Process the data and send output
  metaframe.setOutput("result", value.toUpperCase());
});

// Or listen to all inputs at once
metaframe.onInputs((inputs) => {
  console.log("All inputs:", inputs);
});

Core Concepts

Metapage Definition

A metapage is defined using JSON that specifies which metaframes to load and how they connect:

{
  "version": "2",
  "metaframes": {
    "input": {
      "url": "https://editor.mtfm.io/#?hm=disabled"
    },
    "processor": {
      "url": "https://js.mtfm.io/",
      "inputs": [
        {
          "metaframe": "input",
          "source": "text",
          "target": "code"
        }
      ]
    },
    "output": {
      "url": "https://markdown.mtfm.io/",
      "inputs": [
        {
          "metaframe": "processor",
          "source": "output"
        }
      ]
    }
  }
}

This creates a pipeline: inputprocessoroutput

Metaframe Definition

See code

This is provided either by:

  • https://<your metaframe>/metaframe.json
  • https://<your metaframe>/#?definition=<json encoded hash param>

The definition describes inputs, outputs, security, and the types of hash parameters (so AI tools can correctly modify)

export interface MetaframeDefinitionV2 {
  version: VersionsMetaframe;
  inputs?: {
    [key: string]: MetaframePipeDefinition;
  }; // <MetaframePipeId, MetaframePipeDefinition>
  outputs?: {
    [key: string]: MetaframePipeDefinition;
  }; // <MetaframePipeId, MetaframePipeDefinition>
  metadata: MetaframeMetadataV2;
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Feature_Policy/Using_Feature_Policy#the_iframe_allow_attribute
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy#directives
  allow?: string;
  // Set or override allowed features for the iframe
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox
  sandbox?: string;
  // Hash parameters configuration.
  // Accepts both legacy array format (string[]) and new object format (HashParamsObject).
  // When fetched via helper methods, array format is normalized to object format.
  hashParams?: HashParamsRaw;
}

Data Pipes

Pipes connect metaframe outputs to other metaframe inputs:

{
  "metaframe": "sourceMetaframeId",  // Where data comes from
  "source": "outputPipeName",         // Name of the output pipe
  "target": "inputPipeName"           // Name of the input pipe (optional, defaults to source)
}

Working with Data

The library automatically handles serialization of complex data types:

// In a metaframe - these are automatically serialized when sent between iframes
metaframe.setOutput("file", new File([blob], "data.txt"));
metaframe.setOutput("binary", new Uint8Array([1, 2, 3]));
metaframe.setOutput("buffer", arrayBuffer);

// And automatically deserialized when received
metaframe.onInput("file", (file) => {
  console.log(file instanceof File); // true
});

Usage Examples

Full HTML Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <style>
      body {
        margin: 0;
        padding: 0;
        width: 100vw;
        height: 100vh;
      }
      #metapage-container {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="metapage-container"></div>

    <script type="module">
      import { renderMetapage } from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

      const definition = await fetch(
        "https://metapage.io/m/87ae11673508447e883b598bf7da9c5d/metapage.json",
      ).then((r) => r.json());

      const { setInputs, dispose, metapage } = await renderMetapage({
        definition,
        rootDiv: document.getElementById("metapage-container"),
        onOutputs: (outputs) => {
          console.log("Metaframe outputs:", outputs);
        },
        options: {
          hideFrameBorders: true,
          hideOptions: true,
        },
      });

      // Send inputs to metaframes
      setInputs({
        metaframeId: {
          inputPipeName: "some value",
        },
      });

      // Clean up when done
      // dispose();
    </script>
  </body>
</html>

Building a Metaframe Component

import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

const metaframe = new Metaframe();

// Handle inputs
metaframe.onInputs((inputs) => {
  const { data, config } = inputs;

  // Process inputs
  const result = processData(data, config);

  // Send outputs
  metaframe.setOutputs({
    result: result,
    timestamp: Date.now(),
  });
});

// Individual input listener
metaframe.onInput("reset", () => {
  metaframe.setOutputs({});
});

// Get a specific input value
const currentValue = metaframe.getInput("data");

// Get all inputs
const allInputs = metaframe.getInputs();

// Clean up
metaframe.dispose();

Programmatic Metapage Control

import { Metapage } from "@metapages/metapage";

const metapage = new Metapage({
  definition: {
    version: "2",
    metaframes: {
      viewer: {
        url: "https://markdown.mtfm.io/",
      },
    },
  },
});

// Listen to metaframe outputs
metapage.on(Metapage.OUTPUTS, (outputs) => {
  console.log("Outputs from all metaframes:", outputs);
});

// Set inputs to metaframes
await metapage.setInputs({
  viewer: {
    text: "# Hello World",
  },
});

// Get current outputs
const outputs = metapage.getState().metaframes.outputs;

// Clean up
metapage.dispose();

Advanced Features

Hash Parameters in Metaframes

Metaframes can read and write to their URL hash parameters:

import {
  getHashParamValueJsonFromWindow,
  setHashParamValueJsonInWindow,
} from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

// Read from URL hash
const config = getHashParamValueJsonFromWindow("config");

// Write to URL hash
setHashParamValueJsonInWindow("config", { theme: "dark" });

Pattern Matching in Pipes

Use glob patterns to match multiple outputs:

{
  "inputs": [
    {
      "metaframe": "source",
      "source": "data/*",     // Matches data/foo, data/bar, etc.
      "target": "inputs/"
    }
  ]
}

Binary Data Handling

// Send binary data
const imageData = await fetch("/image.png").then((r) => r.arrayBuffer());
metaframe.setOutput("image", imageData);

// Receive and use
metaframe.onInput("image", async (data) => {
  const blob = new Blob([data]);
  const url = URL.createObjectURL(blob);
  document.getElementById("img").src = url;
});

API Overview

renderMetapage(options)

Render a metapage into a DOM element.

Parameters:

  • definition: Metapage definition object
  • rootDiv: DOM element to render into
  • onOutputs: Callback for metaframe outputs (optional)
  • options: Rendering options (optional)
    • hideBorder: Hide metapage border
    • hideFrameBorders: Hide individual metaframe borders
    • hideOptions: Hide options panel
    • hideMetaframeLabels: Hide metaframe labels

Returns: { setInputs, setOutputs, dispose, metapage }

Metapage Class

Methods:

  • setInputs(inputs): Set inputs for metaframes
  • getState(): Get current state (inputs/outputs)
  • dispose(): Clean up and remove all listeners
  • on(event, handler): Listen to events

Events:

  • Metapage.OUTPUTS: When metaframe outputs change
  • Metapage.INPUTS: When metapage inputs change
  • Metapage.DEFINITION: When definition changes

Metaframe Class

Methods:

  • setOutput(name, value): Set a single output
  • setOutputs(outputs): Set multiple outputs
  • getInput(name): Get a single input value
  • getInputs(): Get all input values
  • onInput(name, callback): Listen to specific input
  • onInputs(callback): Listen to all inputs
  • dispose(): Clean up

Properties:

  • id: Metaframe ID assigned by parent metapage
  • isInputOutputBlobSerialization: Enable/disable automatic binary serialization

Creating Your Own Metaframes

Any web application can become a metaframe by:

  1. Loading the library
  2. Creating a Metaframe instance
  3. Listening for inputs
  4. Sending outputs

Example minimal metaframe:

<!DOCTYPE html>
<html>
  <head>
    <title>My Metaframe</title>
  </head>
  <body>
    <script type="module">
      import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

      const metaframe = new Metaframe();

      metaframe.onInputs((inputs) => {
        // Your logic here
        metaframe.setOutput("result", "processed: " + JSON.stringify(inputs));
      });
    </script>
  </body>
</html>

TypeScript Support

Full TypeScript definitions are included:

import {
  Metapage,
  Metaframe,
  MetapageDefinitionV2,
  MetaframeInputMap,
  MetapageInstanceInputs,
} from "https://cdn.jsdelivr.net/npm/@metapages/[email protected]";

const definition: MetapageDefinitionV2 = {
  version: "2",
  metaframes: {
    example: {
      url: "https://example.com",
    },
  },
};

const metapage = new Metapage({ definition });

Browser Support

  • Chrome 78+
  • Modern browsers with ES2020 support
  • ES modules required

License

Apache-2.0

Contributing

Issues and pull requests welcome at https://github.com/metapages/metapage

More Resources