Manifest+ Format

This post is meant to document the work-in-progress specification of the Manifest+ json format which includes additional fields that Foundry doesn’t use but which can still be useful for a package.

This format is a joint effort from The League’s Circus Wranglers and has been brainstormed for the past few months.

The main addition is the inclusion of the media field which can be used for better representing a package in a package browser (The Forge’s Bazaar for example)

This documents the official manifest format (based on the official documentations) :

{
    /*******************************************************************
     * Standard manifest format: Mandatory fields
     ********/
    /* name: Must match the package's folder name */
    "name": "package_name",
    "title": "Package Title",
    "description": "Description of the package",
    /* version: Using a x.y format or a non string field can lead to confusion 
       and problems due to 0.10 being inferior to 0.9 for example when taken as a number */
    "version": "version number in x.y.z format",

    /*******************************************************************
     * Standard manifest format: Optional but highly recommended fields 
     ********/
    "scripts": ["relative/path/to/script.js"],
    "esmodules": ["relative/path/to/esmodule.js"],
    "styles": ["relative/path/to/style.js"],
    /* url: Can be set to the project page or its README in the git repository for example */
    "url": "https://homepage.com",
    /* manifest: Be careful not to point to the html version on github for example, always point 
      to the raw file and always to the latest manifest file otherwise the package wouldn't be updateable */
    "manifest": "https://link.com/to/raw.module.json",
    /* download: Point this to the zip file archive of the latest version. Do not point this to your master repository branch
       but instead to a version tag, otherwise you risk having users downloading the wrong version */
    "download": "https://github.com/kakaroto/fvtt-module-lmrtfy/archive/v1.3.zip",
    /* minimumCoreVersion: If set, the package cannot be installed on Foundry versions inferior to this */
    "minimumCoreVersion": "0.6.0",
    /* compatibleCoreVersion: if not set, or if set to a value inferior to the current Foundry version, 
       a warning will appear to the user about compatibility risk*/
    "compatibleCoreVersion": "0.7.5"

    /*******************************************************************
     * Standard manifest format: Optional fields
     ********/
    /* type: Specify the package type, can be 'module', 'system' or 'world'.
       This is useful if the manifest file isn't 'module.json', 'system.json' or 'world.json' */
    "type": "module",
    /* systems: Array of systems that the package requires, set to null for system agnostic.
       An empty array means it does not support any system at all */
    "systems": ["system_name"], 
    "packs": [{
        "name": "name_of_the_compendium",
        "label": "The label/title of the pack",
        "path": "relative/path/to/pack.db",
        /* entity: The entity name can be: Actor, JournalEntry, Scene, Item, Macro, Playlist */
        "entity": "EntityName"
     }],
     /* author: For multiple authors, or providing extra information, you can use the authors field, 
        but this field must be filled as it is what Foundry will display */
    "author": "The League",
    /* authors: You can specify a list of authors with more information about each individual author,
       Some of these fields are additions from the manifest+ specification */
    "authors": [{
        "name": "Name of the author",
        "url": "https://website.com/of/the/author",
        "email": "email@example.com",
        /* discord: Manifest+ addition */
        "discord": "discordID#0001"
        /* twitter: Manifest+ addition */
        "twitter": "@TwitterHandle"
        /* reddit: Manifest+ addition */
        "reddit": "u/RedditUsername"
        /* You can add other social media links like discord, twitter, reddit */
    }],
    "languages": [
        {
            /* lang: 2 letter language code, or 2 language code with 2 letter country code such as pt-BZ */
            "lang": "en",
            /* name: The language name, use the translated name, for example 'Español' instead of 'Spanish' */
            "name": "English",
            /* path: Relative path to the translation json file */
            "path": "lang/en.json"
        }
    ],
    /* dependencies: If your module depends on functionality from another module, add it here so
       it can be installed alongside it, and enabled automatically by Foundry. 
       Do not assume it will always be enabled. */
    "dependencies": [
       /* name: This needs to be the dependency name (not title) but it is what will be displayed in Foundry */
       "name": "module_name",
       /* type: The type can be 'module' or 'system', defaulting to 'module'. */
       "type": "module",
       /* manifest: Specifying the manifest ensures it can be installed at the same time if it's not already */
       "manifest": "https://link.com/to/manifest.json"
    ]
    /* socket: Boolean value representing whether this module uses game.socket.emit with 'module.<name>' message names */
    "socket": true,
    "readme": "https://link.com/to/readme.html",
    "bugs": "https://link.com/to/issue/tracker",
    /* license: Specify the license this package is released under. */
    "license": "relative/path/to/license/file",
    /* changelog: Specify a link to the latest changelog*/
    "changelog": "https://link.com/to/this/versions/changelog",

These are the specific additions from the Manifest+ specification (excluding the additional authors fields listed above) :

{
    /*******************************************************************
     * Manifest+ specification
     * Some of these field can be useful but some are optional. 
     * By definition, everything in manifest+ is optional, but useful to include.
     ********/
    /* media: Use the media field to specify any sort of media files relating to this package's listing.
       this can be used to specify screenshots or video tutorials and the like */
    "media": [
      {
        /* type: The type of media, can be: icon, cover, screenshot, video */
        "type": "screenshot",
        /* url: This can be a relative path to the media file, or a URL to it (youtube link for example)
           it is recommend to use web accessible URLs rather than relative paths, otherwise a screenshot 
          or cover image would not be accessible unless the zip download was first downloaded and extracted
         */
        "url": "link/to/media/file"
      }
    ]
    /* library: Set to true if this module is a library module and should not be shown in a UI, or shouldn't be user browsable/installable */
    "library": true,
    /* includes: List the files to be included in this package. Can be useful for automatic CI/CD pipelines 
       generating a zip archive or to make sure that no file is missing from a package */
    "includes": ["relative/path/to/files"],
}

Here it is described in a different and easier to read format :

export interface Manifest{
  name: string,
  title: string,
  description: string,
  version: string,
  author: string,
  minimumCoreVersion: string,

  compatibleCoreVersion?:string,
  scripts?: string[],
  esmodules?: string[],
  styles?: string[],
  packs?: Pack[],
  dependencies?: Dependency[],
  languages?: Language[],
  systems?: string[],
  authors?: Author[],
  socket?: boolean,
  url?: string,
  manifest?: string,
  download?: string,
  license?: string,
  readme?: string,
  bugs?: string,
  changelog?: string

  includes?: string[], // Manifest+  
  media?: Media[] // Manifest+
  library: boolean // Manifest+
}

interface Author {
  name: string,
  email?: string,
  url?: string,
  discord?: string // Manifest+
  twitter?: string // Manifest+
  reddit?: string // Manifest+
}

interface Pack {
  name: string,
  label: string,
  path: string,
  entity: string
}

interface Dependency {
  name?: string,
  type?: Type,
  manifest: string
}

enum Type {
  world = "world",
  system = "system",
  module = "module"
}

interface Language {
  lang: string,
  name: string,
  path: string
}

// Manifest+
interface Media {
  type: MediaType,
  url: string
}

enum MediaType {
  icon = "icon",
  cover= "cover",
  screenshot = "screenshot",
  video = "video"
}
1 Like