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
| Property | Type | Description |
|---|---|---|
| name | String | The visible display name of the calendar. |
| id | String | A unique, URL-safe identifier for the preset. |
| description | String | A short summary of the calendar’s lore or rules. |
Time & Date Settings
| Object | Property | Type | Description |
|---|---|---|---|
| years | yearZero | Integer | The numeric value of the first recorded year. |
| firstWeekday | Integer | (Optional) If true, it marks the day as a weekend/holiday. | |
| resetWeekdays | Boolean | (Optional) If true, the first day of the month will be the first day of the week. | |
| leapYear | Object | Defines leap year logic. leapInterval is the years between leaps. | |
| months | ordinal | Integer | Sequence number (1 for 1st month, 2 for 2nd). |
| days | Integer | Standard number of days in this month. | |
| leapDays | Integer | (Optional) Overrides days during a leap year. | |
| Intercalary | Boolean | (Optional) Should the month be Intercalary. | |
| days | ordinal | Integer | Sequence number for the day of the week. |
| isRestDay | Boolean | (Optional) If true, marks the day as a weekend/holiday. |
Moons
| Property | Type | Description |
|---|---|---|
| firstNewMoon .month | Integer | 1-based index (e.g., 1 for the first month). |
| firstNewMoon .day | Integer | 1-based index (e.g., 1 for the first day). |
| phases.name | String | The name of the phase. Note: Must match standard names (e.g., “Full Moon”) for built-in art. |
| phases.display | String | The 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
| Property | Type | Description |
|---|---|---|
| monthStart / monthEnd | Integer | The Ordinal number of the month (e.g., 1 for Jan, 12 for Dec). |
| dawn / dusk | Number | The 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.
| Property | Type | Description |
|---|---|---|
| name | String | Must be Winter, Summer, Autumn or Spring |
| monthStart / monthEnd | Integer | The Ordinal number of the month (e.g., 1 for Jan, 12 for Dec). |
| tempOffset | Number | Adjusts the weather forecast temperature (fahrenheit) |
Notes
| Property | Type | Description |
| title | String | The name of the event or holiday as it appears on the calendar. |
| content | String | The details or lore of the event. This text appears in tooltips or note dialogues. |
| icon | String | A FontAwesome class string (e.g., “fas fa-skull”, “fas fa-birthday-cake”) used to represent the event on the calendar grid. |
| playerVisible | Boolean | If true the note is visible to player user. (optional, defaults to false) |
| date | Object | The starting date of the event containing year, month, and day. |
| year | Number | The specific year the event starts. Use 0 for generic holidays that repeat every year, regardless of the particular year. |
| month | Number | The month index for the event. Typically matches the index of your months array. |
| day | Number | The day of the month the event occurs. |
| repeatUnit | String | Defines the recurrence logic. Options are: “days”, “months”, “years”, or “none” (for one-time events). |
| repeatInterval | Number | How often does the event repeat based on the unit? Example: 1 For every year, 4 every four years (like leap-year events). |
| repeatCount | Number | The total number of times the event repeats. Set to 0 for infinite repetition. |
| isPreset | Boolean | Recommended 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
}
]
}
}