Custom Calendars

To create a custom calendar, you must provide a JSON object matching the following structure.

An online tool such as JSONLint is an excellent way to validate and fix JSON formatting errors.

General Template

{
  "name": "String (Visible Name)",
  "id": "String (Unique Identifier)",
  "description": "String (Description)",
  "years": {
    "yearZero": Number,
    "firstWeekday": Number (Index usually 0-6),
    "resetWeekdays": Boolean,
    "leapYear": {
      "leapStart": Number,
      "leapInterval": Number
    }
  },
  "months": {
    "values": [
      {
        "name": "String",
        "abbreviation": "String",
        "ordinal": Number (Sequential 1+),
        "days": Number,
        "leapDays": Number (Optional),
        "intercalary": Boolean (Optional)
      }
    ]
  },
  "days": {
    "values": [
      {
        "name": "String",
        "abbreviation": "String",
        "ordinal": Number (Sequential 1+),
        "isRestDay": Boolean (Optional)
      }
    ],
    "daysPerYear": Number,
    "hoursPerDay": Number,
    "minutesPerHour": Number,
    "secondsPerMinute": Number
  },
  "moons": {
    "values": [
      {
        "name": "String",
        "cycleLength": Number (Float),
        "offset": Number,
        "color": "String (Hex Code)",
        "firstNewMoon": {
          "year": Number,
          "month": Number (1-based index, e.g., 1 for Jan),
          "day": Number
        },
        "phases": [
          {
            "name": "String",
            "display": "String",
            "length": Number (Float),
            "icon": "String (FontAwesome Class)"
          }
        ]
      }
    ]
  },
  "sun": {
    "values": [
      {
        "dawn": Number (Hour of the day),
        "dusk": Number (Hour of the day),
        "monthStart": Number (Ordinal),
        "monthEnd": Number (Ordinal)
      }
    ]
  },
  "seasons": {
    "values": [
      {
        "name": "String",
        "monthStart": Number (Ordinal),
        "monthEnd": Number (Ordinal)
      }
    ]
  },
  "weather": {
    "values": [
      {
        "name": "Winter, Summer, Autumn, Spring",
        "monthStart": Number (Ordinal),
        "monthEnd": Number (Ordinal),
        "tempOffset": Number
      }
    ]
  },
  "notes": [
    {
      "title": "String (Event Title)",
      "content": "String (Description)",
      "icon": "String (FontAwesome Class)",
      "playerVisible": Boolean,
      "date": {
        "year": Number,
        "month": Number (Month Index),
        "day": Number (Day of Month)
      },
      "repeatUnit": "String (years, months, days, none)",
      "repeatInterval": Number,
      "repeatCount": Number,
      "isPreset": Boolean
    }
  ]
}

Property Definitions

Global Settings

PropertyTypeDescription
nameStringThe visible display name of the calendar.
idStringA unique, URL-safe identifier for the preset.
descriptionStringA short summary of the calendar’s lore or rules.

Time & Date Settings

ObjectPropertyTypeDescription
yearsyearZeroIntegerThe numeric value of the first recorded year.
firstWeekdayInteger(Optional) If true, it marks the day as a weekend/holiday.
resetWeekdaysBoolean(Optional) If true, the first day of the month will be the first day of the week.
leapYearObjectDefines leap year logic. leapInterval is the years between leaps.
monthsordinalIntegerSequence number (1 for 1st month, 2 for 2nd).
daysIntegerStandard number of days in this month.
leapDaysInteger(Optional) Overrides days during a leap year.
IntercalaryBoolean(Optional) Should the month be Intercalary.
daysordinalIntegerSequence number for the day of the week.
isRestDayBoolean(Optional) If true, marks the day as a weekend/holiday.

Moons

PropertyTypeDescription
firstNewMoon
.month
Integer1-based index (e.g., 1 for the first month).
firstNewMoon
.day
Integer1-based index (e.g., 1 for the first day).
phases.nameStringThe name of the phase.
Note: Must match standard names (e.g., “Full Moon”) for built-in art.
phases.displayStringThe name of the moon phase to display in tooltips.

Moon Phases

Note: To use the built-in moon icons, phase names must match standard English names (e.g., “New Moon”, “Waxing Crescent”, “First Quarter”, “Waxing Gibbous”, “Full Moon”, “Waning Gibbous”, “Last Quarter” and “Waning Crescent”)

Sun & Seasons

PropertyTypeDescription
monthStart / monthEndIntegerThe Ordinal number of the month (e.g., 1 for Jan, 12 for Dec).
dawn / duskNumberThe hour of the day (0-24) when the sun state changes.

Weather

This is the ground truth for weather forecasts. If it isn’t set, it will look for standard season names in Seasons, and if none are found, forecasts will just divide the year into four and arbitrarily assign seasons.

PropertyTypeDescription
nameStringMust be Winter, Summer, Autumn or Spring
monthStart / monthEndIntegerThe Ordinal number of the month (e.g., 1 for Jan, 12 for Dec).
tempOffsetNumberAdjusts the weather forecast temperature (fahrenheit)

Notes

PropertyTypeDescription
titleStringThe name of the event or holiday as it appears on the calendar.
contentStringThe details or lore of the event. This text appears in tooltips or note dialogues.
iconStringA FontAwesome class string (e.g., “fas fa-skull”, “fas fa-birthday-cake”) used to represent the event on the calendar grid.
playerVisibleBooleanIf true the note is visible to player user. (optional, defaults to false)
dateObjectThe starting date of the event containing year, month, and day.
  yearNumberThe specific year the event starts. Use 0 for generic holidays that repeat every year, regardless of the particular year.
  monthNumberThe month index for the event. Typically matches the index of your months array.
  dayNumberThe day of the month the event occurs.
repeatUnitStringDefines the recurrence logic. Options are: “days”, “months”, “years”, or “none” (for one-time events).
repeatIntervalNumberHow often does the event repeat based on the unit? Example: 1 For every year, 4 every four years (like leap-year events).
repeatCountNumberThe total number of times the event repeats. Set to 0 for infinite repetition.
isPresetBooleanRecommended to set to true. This internal flag helps the importer detect and prevent duplicates if a user re-imports the same calendar configuration.

Example Harptos JSON

{
  "name": "Harptos (Forgotten Realms)",
  "id": "harptos-preset",
  "description": "The standard calendar of the Forgotten Realms.",
  "years": {
    "yearZero": 0,
    "firstWeekday": 0,
    "leapYear": {
      "leapStart": 0,
      "leapInterval": 4
    }
  },
  "months": {
    "values": [
      {
        "name": "Hammer",
        "abbreviation": "Ham",
        "ordinal": 1,
        "days": 30
      },
      {
        "name": "Midwinter",
        "abbreviation": "Mid",
        "ordinal": 1,
        "days": 1
      },
      {
        "name": "Alturiak",
        "abbreviation": "Alt",
        "ordinal": 2,
        "days": 30
      },
      {
        "name": "Ches",
        "abbreviation": "Che",
        "ordinal": 3,
        "days": 30
      },
      {
        "name": "Tarsakh",
        "abbreviation": "Tar",
        "ordinal": 4,
        "days": 30
      },
      {
        "name": "Greengrass",
        "abbreviation": "Gre",
        "ordinal": 4,
        "days": 1
      },
      {
        "name": "Mirtul",
        "abbreviation": "Mir",
        "ordinal": 5,
        "days": 30
      },
      {
        "name": "Kythorn",
        "abbreviation": "Kyt",
        "ordinal": 6,
        "days": 30
      },
      {
        "name": "Flamerule",
        "abbreviation": "Fla",
        "ordinal": 7,
        "days": 30
      },
      {
        "name": "Midsummer",
        "abbreviation": "MidS",
        "ordinal": 7,
        "days": 1
      },
      {
        "name": "Shieldmeet",
        "abbreviation": "Shi",
        "ordinal": 7,
        "days": 0,
        "leapDays": 1
      },
      {
        "name": "Eleasis",
        "abbreviation": "Ele",
        "ordinal": 8,
        "days": 30
      },
      {
        "name": "Eleint",
        "abbreviation": "Eli",
        "ordinal": 9,
        "days": 30
      },
      {
        "name": "Highharvestide",
        "abbreviation": "Hig",
        "ordinal": 9,
        "days": 1
      },
      {
        "name": "Marpenoth",
        "abbreviation": "Mar",
        "ordinal": 10,
        "days": 30
      },
      {
        "name": "Uktar",
        "abbreviation": "Ukt",
        "ordinal": 11,
        "days": 30
      },
      {
        "name": "Feast of the Moon",
        "abbreviation": "Fea",
        "ordinal": 11,
        "days": 1
      },
      {
        "name": "Nightal",
        "abbreviation": "Nig",
        "ordinal": 12,
        "days": 30
      }
    ]
  },
  "days": {
    "values": [
      {
        "name": "First-day",
        "abbreviation": "1d",
        "ordinal": 1
      },
      {
        "name": "Second-day",
        "abbreviation": "2d",
        "ordinal": 2
      },
      {
        "name": "Third-day",
        "abbreviation": "3d",
        "ordinal": 3
      },
      {
        "name": "Fourth-day",
        "abbreviation": "4d",
        "ordinal": 4
      },
      {
        "name": "Fifth-day",
        "abbreviation": "5d",
        "ordinal": 5
      },
      {
        "name": "Sixth-day",
        "abbreviation": "6d",
        "ordinal": 6
      },
      {
        "name": "Seventh-day",
        "abbreviation": "7d",
        "ordinal": 7
      },
      {
        "name": "Eighth-day",
        "abbreviation": "8d",
        "ordinal": 8
      },
      {
        "name": "Ninth-day",
        "abbreviation": "9d",
        "ordinal": 9
      },
      {
        "name": "Tenth-day",
        "abbreviation": "10d",
        "ordinal": 10
      }
    ],
    "daysPerYear": 365,
    "hoursPerDay": 24,
    "minutesPerHour": 60,
    "secondsPerMinute": 60
  },
  "moons": {
    "values": [
      {
        "name": "Selûne",
        "cycleLength": 30.4375,
        "offset": 0,
        "phases": [
          {
            "name": "New Moon",
            "display": "New Moon",
            "length": 3.8,
            "icon": "fa-moon"
          },
          {
            "name": "Waxing Crescent",
            "display": "Waxing Crescent",
            "length": 3.8,
            "icon": "fa-moon"
          },
          {
            "name": "First Quarter",
            "display": "First Quarter",
            "length": 3.8,
            "icon": "fa-adjust"
          },
          {
            "name": "Waxing Gibbous",
            "display": "Waxing Gibbous",
            "length": 3.8,
            "icon": "fa-moon"
          },
          {
            "name": "Full Moon",
            "display": "Full Moon",
            "length": 3.8,
            "icon": "fa-circle"
          },
          {
            "name": "Waning Gibbous",
            "display": "Waning Gibbous",
            "length": 3.8,
            "icon": "fa-moon"
          },
          {
            "name": "Last Quarter",
            "display": "Last Quarter",
            "length": 3.8,
            "icon": "fa-adjust fa-flip-horizontal"
          },
          {
            "name": "Waning Crescent",
            "display": "Waning Crescent",
            "length": 3.8,
            "icon": "fa-moon"
          }
        ],
        "color": "#e0e0e0",
        "firstNewMoon": {
          "year": 1,
          "month": 1,
          "day": 1
        }
      }
    ]
  },
  "sun": {
    "values": [
      {
        "dawn": 8,
        "dusk": 16,
        "monthStart": 1,
        "monthEnd": 2
      },
      {
        "dawn": 6,
        "dusk": 18,
        "monthStart": 3,
        "monthEnd": 5
      },
      {
        "dawn": 5,
        "dusk": 20,
        "monthStart": 6,
        "monthEnd": 8
      },
      {
        "dawn": 6,
        "dusk": 18,
        "monthStart": 9,
        "monthEnd": 11
      },
      {
        "dawn": 8,
        "dusk": 16,
        "monthStart": 12,
        "monthEnd": 12
      }
    ]
  },
  "notes": [
    {
      "title": "Midwinter",
      "content": "Midwinter (also known as Deadwinter Day) was a festival to mark the midpoint of winter.",
      "icon": "fas fa-snowflake",
      "date": {
        "year": 0,
        "month": 1,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Spring Equinox",
      "content": "The first day of spring.",
      "icon": "fas fa-seedling",
      "date": {
        "year": 0,
        "month": 3,
        "day": 18
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Greengrass",
      "content": "Greengrass is a festival to welcome in the first day of spring.",
      "icon": "fas fa-leaf",
      "date": {
        "year": 0,
        "month": 5,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Summer Solstice",
      "content": "The longest day of the year.",
      "icon": "fas fa-sun",
      "date": {
        "year": 0,
        "month": 7,
        "day": 19
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Midsummer",
      "content": "Midsummer is a festival that celebrated love and music through feast.",
      "icon": "fas fa-wine-glass-alt",
      "date": {
        "year": 0,
        "month": 9,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Shieldmeet",
      "content": "A leap year festival occurring once every four years.",
      "icon": "fas fa-shield-alt",
      "date": {
        "year": 0,
        "month": 10,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Autumn Equinox",
      "content": "The changing of the seasons to autumn.",
      "icon": "fas fa-balance-scale",
      "date": {
        "year": 0,
        "month": 12,
        "day": 20
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Highharvestide",
      "content": "A feast to celebrate the harvest.",
      "icon": "fas fa-wheat",
      "date": {
        "year": 0,
        "month": 13,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Feast of the Moon",
      "content": "A festival honoring the ancestors and the dead.",
      "icon": "fas fa-moon",
      "date": {
        "year": 0,
        "month": 16,
        "day": 0
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    },
    {
      "title": "Winter Solstice",
      "content": "The shortest day of the year.",
      "icon": "fas fa-star",
      "date": {
        "year": 0,
        "month": 17,
        "day": 19
      },
      "repeatUnit": "years",
      "repeatInterval": 1,
      "repeatCount": 0,
      "isPreset": true
    }
  ],
  "seasons": {
    "values": [
      {
        "name": "Deepwinter",
        "monthStart": 1,
        "monthEnd": 1
      },
      {
        "name": "The Claw of Winter",
        "monthStart": 2,
        "monthEnd": 2
      },
      {
        "name": "The Claw of Sunsets",
        "monthStart": 3,
        "monthEnd": 3
      },
      {
        "name": "The Claw of Storms",
        "monthStart": 4,
        "monthEnd": 4
      },
      {
        "name": "The Melting",
        "monthStart": 5,
        "monthEnd": 5
      },
      {
        "name": "The Time of Flowers",
        "monthStart": 6,
        "monthEnd": 6
      },
      {
        "name": "Summertide",
        "monthStart": 7,
        "monthEnd": 7
      },
      {
        "name": "Highsun",
        "monthStart": 8,
        "monthEnd": 8
      },
      {
        "name": "The Fading",
        "monthStart": 9,
        "monthEnd": 9
      },
      {
        "name": "Leaffall",
        "monthStart": 10,
        "monthEnd": 10
      },
      {
        "name": "The Rotting",
        "monthStart": 11,
        "monthEnd": 11
      },
      {
        "name": "The Drawing Down",
        "monthStart": 12,
        "monthEnd": 12
      }
    ]
  },
  "weather": {
    "values": [
      {
        "name": "Winter",
        "monthStart": 1,
        "monthEnd": 2,
        "tempOffset": -10
      },
      {
        "name": "Spring",
        "monthStart": 3,
        "monthEnd": 5,
        "tempOffset": 0
      },
      {
        "name": "Summer",
        "monthStart": 6,
        "monthEnd": 8,
        "tempOffset": 15
      },
      {
        "name": "Autumn",
        "monthStart": 9,
        "monthEnd": 11,
        "tempOffset": 5
      },
      {
        "name": "Winter",
        "monthStart": 12,
        "monthEnd": 12,
        "tempOffset": -10
      }
    ]
  }
}