Compare commits
85 Commits
c6d04b9b3b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a67e3c5763 | ||
|
|
b810c9cbaf | ||
|
|
d55d52c538 | ||
|
|
faa867956a | ||
|
|
5b3e405b99 | ||
|
|
30e624fa64 | ||
|
|
41494785ca | ||
|
|
4196a72615 | ||
|
|
9a4ef773dc | ||
|
|
7e67233dea | ||
|
|
6ca3098432 | ||
|
|
1a3a5b7cff | ||
|
|
b40ee5eea6 | ||
|
|
c684651cef | ||
|
|
3dffd847de | ||
|
|
9f7ecd9cd0 | ||
|
|
25e678af8d | ||
|
|
cc2c5eb973 | ||
|
|
8c02a07b88 | ||
|
|
7da6549bf9 | ||
|
|
2e6c1534b1 | ||
|
|
0a301564ac | ||
|
|
85e69a0b34 | ||
|
|
5adaf202ae | ||
|
|
99ac46a384 | ||
|
|
3a2750388b | ||
|
|
33e89ec16b | ||
|
|
9adbe92e7c | ||
|
|
103d63f1b1 | ||
|
|
49bad2e880 | ||
|
|
04616c2ac4 | ||
|
|
3b73dd1728 | ||
|
|
d5df90a6ae | ||
|
|
494e475f42 | ||
|
|
4703ba48ed | ||
|
|
93d5686b77 | ||
|
|
71d07aa0f3 | ||
|
|
c43f031617 | ||
|
|
89ce903e8a | ||
|
|
cbf5d73629 | ||
|
|
8be17dae74 | ||
|
|
76006dc162 | ||
|
|
492acb4052 | ||
|
|
68dc9efa4d | ||
|
|
7b15ed46c1 | ||
|
|
8019ba760f | ||
|
|
9d1a268875 | ||
|
|
9e5feafd64 | ||
|
|
5283a69bb8 | ||
|
|
a4b2d2edd5 | ||
|
|
d0634e4487 | ||
|
|
79c4f988f2 | ||
|
|
cee1fa6736 | ||
|
|
8510674d58 | ||
|
|
5ee724201b | ||
|
|
b85c038df0 | ||
|
|
3d4e04ab0f | ||
|
|
b1d1ce79e6 | ||
|
|
0b7b506b8d | ||
|
|
f3ea84cc80 | ||
|
|
3d9a474aae | ||
|
|
db5baa1fd7 | ||
|
|
72ad4ee1a4 | ||
|
|
bb6c7796d5 | ||
|
|
bd8088c52b | ||
|
|
3c1bd01373 | ||
|
|
669ac6d3da | ||
|
|
73f9be91ef | ||
|
|
f14785c54a | ||
|
|
296873f89e | ||
|
|
d6a9ff7176 | ||
|
|
ef15857533 | ||
|
|
19b21ba94f | ||
|
|
8f322fd6cf | ||
|
|
bdc7d2e325 | ||
|
|
8afe397c23 | ||
|
|
30c29d440f | ||
|
|
69adc64a44 | ||
|
|
b0fae10aa1 | ||
|
|
cee4dae769 | ||
|
|
f9aeeadccf | ||
|
|
fc35fcd3c4 | ||
|
|
6a83981e1d | ||
|
|
540d7f9baa | ||
|
|
a162b30bcd |
@@ -18,40 +18,40 @@ public class PluginConfiguration : BasePluginConfiguration
|
|||||||
EnableClientSideToggle = true;
|
EnableClientSideToggle = true;
|
||||||
|
|
||||||
Autumn = new AutumnOptions();
|
Autumn = new AutumnOptions();
|
||||||
Snowflakes = new SnowflakesOptions();
|
Birthday = new BirthdayOptions();
|
||||||
Snowfall = new SnowfallOptions();
|
Carnival = new CarnivalOptions();
|
||||||
Snowstorm = new SnowstormOptions();
|
CherryBlossom = new CherryBlossomOptions();
|
||||||
|
Christmas = new ChristmasOptions();
|
||||||
|
EarthDay = new EarthDayOptions();
|
||||||
|
Easter = new EasterOptions();
|
||||||
|
Eid = new EidOptions();
|
||||||
|
Eurovision = new EurovisionOptions();
|
||||||
|
FilmNoir = new FilmNoirOptions();
|
||||||
Fireworks = new FireworksOptions();
|
Fireworks = new FireworksOptions();
|
||||||
|
Friday13 = new Friday13Options();
|
||||||
|
Frost = new FrostOptions();
|
||||||
Halloween = new HalloweenOptions();
|
Halloween = new HalloweenOptions();
|
||||||
Hearts = new HeartsOptions();
|
Hearts = new HeartsOptions();
|
||||||
Christmas = new ChristmasOptions();
|
|
||||||
Santa = new SantaOptions();
|
|
||||||
Easter = new EasterOptions();
|
|
||||||
Resurrection = new ResurrectionOptions();
|
|
||||||
Spring = new SpringOptions();
|
|
||||||
Summer = new SummerOptions();
|
|
||||||
CherryBlossom = new CherryBlossomOptions();
|
|
||||||
Carnival = new CarnivalOptions();
|
|
||||||
PiDay = new PiDayOptions();
|
|
||||||
Eurovision = new EurovisionOptions();
|
|
||||||
Storm = new StormOptions();
|
|
||||||
Pride = new PrideOptions();
|
|
||||||
EarthDay = new EarthDayOptions();
|
|
||||||
Rain = new RainOptions();
|
|
||||||
Frost = new FrostOptions();
|
|
||||||
FilmNoir = new FilmNoirOptions();
|
|
||||||
Oscar = new OscarOptions();
|
|
||||||
MarioDay = new MarioDayOptions();
|
MarioDay = new MarioDayOptions();
|
||||||
StarWars = new StarWarsOptions();
|
Matrix = new MatrixOptions();
|
||||||
Oktoberfest = new OktoberfestOptions();
|
Oktoberfest = new OktoberfestOptions();
|
||||||
Friday13 = new Friday13Options();
|
Olympia = new OlympiaOptions();
|
||||||
Eid = new EidOptions();
|
Oscar = new OscarOptions();
|
||||||
|
Rain = new RainOptions();
|
||||||
|
Pride = new PrideOptions();
|
||||||
|
Resurrection = new ResurrectionOptions();
|
||||||
|
Santa = new SantaOptions();
|
||||||
|
Snowfall = new SnowfallOptions();
|
||||||
|
Snowflakes = new SnowflakesOptions();
|
||||||
|
Snowstorm = new SnowstormOptions();
|
||||||
|
Space = new SpaceOptions();
|
||||||
Spooky = new SpookyOptions();
|
Spooky = new SpookyOptions();
|
||||||
Sports = new SportsOptions();
|
Sports = new SportsOptions();
|
||||||
Olympia = new OlympiaOptions();
|
Spring = new SpringOptions();
|
||||||
Space = new SpaceOptions();
|
StarWars = new StarWarsOptions();
|
||||||
|
Storm = new StormOptions();
|
||||||
|
Summer = new SummerOptions();
|
||||||
Underwater = new UnderwaterOptions();
|
Underwater = new UnderwaterOptions();
|
||||||
Birthday = new BirthdayOptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -77,349 +77,338 @@ public class PluginConfiguration : BasePluginConfiguration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the seasonal rules configuration as JSON.
|
/// Gets or sets the seasonal rules configuration as JSON.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SeasonalRules { get; set; } = "[{\"Name\":\"New Year Fireworks\",\"StartDay\":28,\"StartMonth\":12,\"EndDay\":5,\"EndMonth\":1,\"Theme\":\"fireworks\"},{\"Name\":\"Carnival\",\"StartDay\":19,\"StartMonth\":2,\"EndDay\":28,\"EndMonth\":2,\"Theme\":\"carnival\"},{\"Name\":\"Valentine's Day\",\"StartDay\":10,\"StartMonth\":2,\"EndDay\":18,\"EndMonth\":2,\"Theme\":\"hearts\"},{\"Name\":\"Spring\",\"StartDay\":1,\"StartMonth\":3,\"EndDay\":31,\"EndMonth\":5,\"Theme\":\"spring\"},{\"Name\":\"Summer\",\"StartDay\":1,\"StartMonth\":6,\"EndDay\":31,\"EndMonth\":8,\"Theme\":\"summer\"},{\"Name\":\"Santa\",\"StartDay\":22,\"StartMonth\":12,\"EndDay\":27,\"EndMonth\":12,\"Theme\":\"santa\"},{\"Name\":\"Snowflakes (December)\",\"StartDay\":1,\"StartMonth\":12,\"EndDay\":31,\"EndMonth\":12,\"Theme\":\"snowflakes\"},{\"Name\":\"Snowfall (January)\",\"StartDay\":1,\"StartMonth\":1,\"EndDay\":31,\"EndMonth\":1,\"Theme\":\"snowfall\"},{\"Name\":\"Snowfall (February)\",\"StartDay\":1,\"StartMonth\":2,\"EndDay\":29,\"EndMonth\":2,\"Theme\":\"snowfall\"},{\"Name\":\"Easter\",\"StartDay\":25,\"StartMonth\":3,\"EndDay\":25,\"EndMonth\":4,\"Theme\":\"easter\"},{\"Name\":\"Halloween\",\"StartDay\":24,\"StartMonth\":10,\"EndDay\":5,\"EndMonth\":11,\"Theme\":\"halloween\"},{\"Name\":\"Autumn\",\"StartDay\":1,\"StartMonth\":9,\"EndDay\":30,\"EndMonth\":11,\"Theme\":\"autumn\"},{\"Name\":\"Cherry Blossom\",\"StartDay\":1,\"StartMonth\":4,\"EndDay\":30,\"EndMonth\":4,\"Theme\":\"cherryblossom\"}]";
|
public string SeasonalRules { get; set; } = "[" +
|
||||||
|
"{\"Name\":\"New Year Fireworks\",\"StartDay\":28,\"StartMonth\":12,\"EndDay\":5,\"EndMonth\":1,\"Theme\":\"fireworks\"}," +
|
||||||
|
"{\"Name\":\"Snowfall (January)\",\"StartDay\":1,\"StartMonth\":1,\"EndDay\":31,\"EndMonth\":1,\"Theme\":\"snowfall\"}," +
|
||||||
|
"{\"Name\":\"Snowfall (February)\",\"StartDay\":1,\"StartMonth\":2,\"EndDay\":29,\"EndMonth\":2,\"Theme\":\"snowfall\"}," +
|
||||||
|
"{\"Name\":\"Valentine's Day\",\"StartDay\":10,\"StartMonth\":2,\"EndDay\":18,\"EndMonth\":2,\"Theme\":\"hearts\"}," +
|
||||||
|
"{\"Name\":\"Carnival\",\"StartDay\":19,\"StartMonth\":2,\"EndDay\":28,\"EndMonth\":2,\"Theme\":\"carnival\"}," +
|
||||||
|
"{\"Name\":\"Oscar Awards\",\"StartDay\":23,\"StartMonth\":2,\"EndDay\":5,\"EndMonth\":3,\"Theme\":\"oscar\"}," +
|
||||||
|
"{\"Name\":\"Mario Day\",\"StartDay\":10,\"StartMonth\":3,\"EndDay\":10,\"EndMonth\":3,\"Theme\":\"marioday\"}," +
|
||||||
|
"{\"Name\":\"Film Noir Day\",\"StartDay\":17,\"StartMonth\":3,\"EndDay\":17,\"EndMonth\":3,\"Theme\":\"filmnoir\"}," +
|
||||||
|
"{\"Name\":\"Spring\",\"StartDay\":1,\"StartMonth\":3,\"EndDay\":31,\"EndMonth\":5,\"Theme\":\"spring\"}," +
|
||||||
|
"{\"Name\":\"Cherry Blossom\",\"StartDay\":1,\"StartMonth\":4,\"EndDay\":30,\"EndMonth\":4,\"Theme\":\"cherryblossom\"}," +
|
||||||
|
"{\"Name\":\"Easter\",\"StartDay\":25,\"StartMonth\":3,\"EndDay\":25,\"EndMonth\":4,\"Theme\":\"easter\"}," +
|
||||||
|
"{\"Name\":\"Earth Day\",\"StartDay\":22,\"StartMonth\":4,\"EndDay\":22,\"EndMonth\":4,\"Theme\":\"earthday\"}," +
|
||||||
|
"{\"Name\":\"Space Day\",\"StartDay\":12,\"StartMonth\":4,\"EndDay\":12,\"EndMonth\":4,\"Theme\":\"space\"}," +
|
||||||
|
"{\"Name\":\"Star Wars Day\",\"StartDay\":4,\"StartMonth\":5,\"EndDay\":5,\"EndMonth\":5,\"Theme\":\"starwars\"}," +
|
||||||
|
"{\"Name\":\"Eurovision\",\"StartDay\":6,\"StartMonth\":5,\"EndDay\":12,\"EndMonth\":5,\"Theme\":\"eurovision\"}," +
|
||||||
|
"{\"Name\":\"Pride Month\",\"StartDay\":1,\"StartMonth\":6,\"EndDay\":30,\"EndMonth\":6,\"Theme\":\"pride\"}," +
|
||||||
|
"{\"Name\":\"Summer\",\"StartDay\":1,\"StartMonth\":6,\"EndDay\":31,\"EndMonth\":8,\"Theme\":\"summer\"}," +
|
||||||
|
"{\"Name\":\"Underwater\",\"StartDay\":1,\"StartMonth\":7,\"EndDay\":31,\"EndMonth\":8,\"Theme\":\"underwater\"}," +
|
||||||
|
"{\"Name\":\"Autumn\",\"StartDay\":1,\"StartMonth\":9,\"EndDay\":30,\"EndMonth\":11,\"Theme\":\"autumn\"}," +
|
||||||
|
"{\"Name\":\"Oktoberfest\",\"StartDay\":20,\"StartMonth\":9,\"EndDay\":5,\"EndMonth\":10,\"Theme\":\"oktoberfest\"}," +
|
||||||
|
"{\"Name\":\"Halloween\",\"StartDay\":24,\"StartMonth\":10,\"EndDay\":5,\"EndMonth\":11,\"Theme\":\"halloween\"}," +
|
||||||
|
"{\"Name\":\"Spooky (Pre-Halloween)\",\"StartDay\":1,\"StartMonth\":10,\"EndDay\":23,\"EndMonth\":10,\"Theme\":\"spooky\"}," +
|
||||||
|
"{\"Name\":\"Snowflakes (December)\",\"StartDay\":1,\"StartMonth\":12,\"EndDay\":31,\"EndMonth\":12,\"Theme\":\"snowflakes\"}," +
|
||||||
|
"{\"Name\":\"Santa\",\"StartDay\":22,\"StartMonth\":12,\"EndDay\":27,\"EndMonth\":12,\"Theme\":\"santa\"}" +
|
||||||
|
"]";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Seasonals options.
|
/// Gets or sets the Seasonals options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AutumnOptions Autumn { get; set; }
|
public AutumnOptions Autumn { get; set; }
|
||||||
public SnowflakesOptions Snowflakes { get; set; }
|
public BirthdayOptions Birthday { get; set; }
|
||||||
public SnowfallOptions Snowfall { get; set; }
|
public CarnivalOptions Carnival { get; set; }
|
||||||
public SnowstormOptions Snowstorm { get; set; }
|
public CherryBlossomOptions CherryBlossom { get; set; }
|
||||||
|
public ChristmasOptions Christmas { get; set; }
|
||||||
|
public EarthDayOptions EarthDay { get; set; }
|
||||||
|
public EasterOptions Easter { get; set; }
|
||||||
|
public EidOptions Eid { get; set; }
|
||||||
|
public EurovisionOptions Eurovision { get; set; }
|
||||||
|
public FilmNoirOptions FilmNoir { get; set; }
|
||||||
public FireworksOptions Fireworks { get; set; }
|
public FireworksOptions Fireworks { get; set; }
|
||||||
|
public Friday13Options Friday13 { get; set; }
|
||||||
|
public FrostOptions Frost { get; set; }
|
||||||
public HalloweenOptions Halloween { get; set; }
|
public HalloweenOptions Halloween { get; set; }
|
||||||
public HeartsOptions Hearts { get; set; }
|
public HeartsOptions Hearts { get; set; }
|
||||||
public ChristmasOptions Christmas { get; set; }
|
|
||||||
public SantaOptions Santa { get; set; }
|
|
||||||
public EasterOptions Easter { get; set; }
|
|
||||||
public ResurrectionOptions Resurrection { get; set; }
|
|
||||||
public SpringOptions Spring { get; set; }
|
|
||||||
public SummerOptions Summer { get; set; }
|
|
||||||
public CherryBlossomOptions CherryBlossom { get; set; }
|
|
||||||
public CarnivalOptions Carnival { get; set; }
|
|
||||||
public PiDayOptions PiDay { get; set; }
|
|
||||||
public EurovisionOptions Eurovision { get; set; }
|
|
||||||
public StormOptions Storm { get; set; }
|
|
||||||
public PrideOptions Pride { get; set; }
|
|
||||||
public EarthDayOptions EarthDay { get; set; }
|
|
||||||
public RainOptions Rain { get; set; }
|
|
||||||
public FrostOptions Frost { get; set; }
|
|
||||||
public FilmNoirOptions FilmNoir { get; set; }
|
|
||||||
public OscarOptions Oscar { get; set; }
|
|
||||||
public MarioDayOptions MarioDay { get; set; }
|
public MarioDayOptions MarioDay { get; set; }
|
||||||
public StarWarsOptions StarWars { get; set; }
|
public MatrixOptions Matrix { get; set; }
|
||||||
public OktoberfestOptions Oktoberfest { get; set; }
|
public OktoberfestOptions Oktoberfest { get; set; }
|
||||||
public Friday13Options Friday13 { get; set; }
|
public OlympiaOptions Olympia { get; set; }
|
||||||
public EidOptions Eid { get; set; }
|
public OscarOptions Oscar { get; set; }
|
||||||
|
public PrideOptions Pride { get; set; }
|
||||||
|
public RainOptions Rain { get; set; }
|
||||||
|
public ResurrectionOptions Resurrection { get; set; }
|
||||||
|
public SantaOptions Santa { get; set; }
|
||||||
|
public SnowfallOptions Snowfall { get; set; }
|
||||||
|
public SnowflakesOptions Snowflakes { get; set; }
|
||||||
|
public SnowstormOptions Snowstorm { get; set; }
|
||||||
|
public SpaceOptions Space { get; set; }
|
||||||
public SpookyOptions Spooky { get; set; }
|
public SpookyOptions Spooky { get; set; }
|
||||||
public SportsOptions Sports { get; set; }
|
public SportsOptions Sports { get; set; }
|
||||||
public OlympiaOptions Olympia { get; set; }
|
public SpringOptions Spring { get; set; }
|
||||||
public SpaceOptions Space { get; set; }
|
public StarWarsOptions StarWars { get; set; }
|
||||||
|
public StormOptions Storm { get; set; }
|
||||||
|
public SummerOptions Summer { get; set; }
|
||||||
public UnderwaterOptions Underwater { get; set; }
|
public UnderwaterOptions Underwater { get; set; }
|
||||||
public BirthdayOptions Birthday { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AutumnOptions
|
public class AutumnOptions {
|
||||||
{
|
|
||||||
public int LeafCount { get; set; } = 25;
|
|
||||||
public bool EnableAutumn { get; set; } = true;
|
public bool EnableAutumn { get; set; } = true;
|
||||||
public bool EnableRandomLeaves { get; set; } = true;
|
public int LeafCount { get; set; } = 35;
|
||||||
public bool EnableRandomLeavesMobile { get; set; } = false;
|
public int LeafCountMobile { get; set; } = 10;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
public bool EnableRotation { get; set; } = false;
|
public bool EnableRotation { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SnowflakesOptions
|
public class BirthdayOptions {
|
||||||
{
|
public bool EnableBirthday { get; set; } = true;
|
||||||
public int SnowflakeCount { get; set; } = 25;
|
public int SymbolCount { get; set; } = 12;
|
||||||
public bool EnableSnowflakes { get; set; } = true;
|
public int SymbolCountMobile { get; set; } = 5;
|
||||||
public bool EnableRandomSnowflakes { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
public bool EnableRandomSnowflakesMobile { get; set; } = false;
|
public int ConfettiCount { get; set; } = 60;
|
||||||
public bool EnableColoredSnowflakes { get; set; } = true;
|
}
|
||||||
|
|
||||||
|
public class CarnivalOptions {
|
||||||
|
public bool EnableCarnival { get; set; } = true;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
public bool EnableCarnivalSway { get; set; } = true;
|
||||||
|
public int ObjectCount { get; set; } = 120;
|
||||||
|
public int ObjectCountMobile { get; set; } = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CherryBlossomOptions {
|
||||||
|
public bool EnableCherryBlossom { get; set; } = true;
|
||||||
|
public int PetalCount { get; set; } = 25;
|
||||||
|
public int PetalCountMobile { get; set; } = 15;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SnowfallOptions
|
public class ChristmasOptions {
|
||||||
{
|
public bool EnableChristmas { get; set; } = true;
|
||||||
public int SnowflakesCount { get; set; } = 500;
|
public int SymbolCount { get; set; } = 25;
|
||||||
public int SnowflakesCountMobile { get; set; } = 250;
|
public int SymbolCountMobile { get; set; } = 10;
|
||||||
public double Speed { get; set; } = 3;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
public bool EnableSnowfall { get; set; } = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SnowstormOptions
|
public class EarthDayOptions {
|
||||||
{
|
public bool EnableEarthDay { get; set; } = true;
|
||||||
public int SnowflakesCount { get; set; } = 500;
|
public int FlowersCount { get; set; } = 60;
|
||||||
public int SnowflakesCountMobile { get; set; } = 250;
|
public int FlowersCountMobile { get; set; } = 20;
|
||||||
public double Speed { get; set; } = 6;
|
|
||||||
public bool EnableSnowstorm { get; set; } = true;
|
|
||||||
public double HorizontalWind { get; set; } = 4;
|
|
||||||
public double VerticalVariation { get; set; } = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FireworksOptions
|
public class EasterOptions {
|
||||||
{
|
public bool EnableEaster { get; set; } = true;
|
||||||
public int ParticleCount { get; set; } = 50;
|
public bool EnableBunny { get; set; } = true;
|
||||||
public int LaunchInterval { get; set; } = 3200;
|
public int MinBunnyRestTime { get; set; } = 2000;
|
||||||
|
public int MaxBunnyRestTime { get; set; } = 5000;
|
||||||
|
public int EggCount { get; set; } = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EidOptions {
|
||||||
|
public bool EnableEid { get; set; } = true;
|
||||||
|
public int LanternCount { get; set; } = 8;
|
||||||
|
public int LanternCountMobile { get; set; } = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EurovisionOptions {
|
||||||
|
public bool EnableEurovision { get; set; } = true;
|
||||||
|
public int SymbolCount { get; set; } = 25;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
public bool EnableColorfulNotes { get; set; } = true;
|
||||||
|
public string EurovisionColors { get; set; } = "#ff0026ff,#17a6ffff,#32d432ff,#FFD700,#f0821bff,#f826f8ff";
|
||||||
|
public int EurovisionGlowSize { get; set; } = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FilmNoirOptions {
|
||||||
|
public bool EnableFilmNoir { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FireworksOptions {
|
||||||
public bool EnableFireworks { get; set; } = true;
|
public bool EnableFireworks { get; set; } = true;
|
||||||
public bool ScrollFireworks { get; set; } = true;
|
public bool ScrollFireworks { get; set; } = true;
|
||||||
|
public int ParticleCount { get; set; } = 50;
|
||||||
public int MinFireworks { get; set; } = 3;
|
public int MinFireworks { get; set; } = 3;
|
||||||
public int MaxFireworks { get; set; } = 6;
|
public int MaxFireworks { get; set; } = 6;
|
||||||
|
public int LaunchInterval { get; set; } = 3200;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HalloweenOptions
|
public class Friday13Options {
|
||||||
{
|
public bool EnableFriday13 { get; set; } = true;
|
||||||
public int SymbolCount { get; set; } = 25;
|
}
|
||||||
|
|
||||||
|
public class FrostOptions {
|
||||||
|
public bool EnableFrost { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HalloweenOptions {
|
||||||
public bool EnableHalloween { get; set; } = true;
|
public bool EnableHalloween { get; set; } = true;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
public int SymbolCount { get; set; } = 25;
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
public int SymbolCountMobile { get; set; } = 10;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
public bool EnableSpiders { get; set; } = true;
|
public bool EnableSpiders { get; set; } = true;
|
||||||
public bool EnableMice { get; set; } = true;
|
public bool EnableMice { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HeartsOptions
|
public class HeartsOptions {
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
|
||||||
public bool EnableHearts { get; set; } = true;
|
public bool EnableHearts { get; set; } = true;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChristmasOptions
|
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
public int SymbolCount { get; set; } = 25;
|
||||||
public bool EnableChristmas { get; set; } = true;
|
public int SymbolCountMobile { get; set; } = 10;
|
||||||
public bool EnableRandomChristmas { get; set; } = true;
|
|
||||||
public bool EnableRandomChristmasMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SantaOptions
|
public class MarioDayOptions {
|
||||||
{
|
public bool EnableMarioDay { get; set; } = true;
|
||||||
|
public bool LetMarioJump { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixOptions {
|
||||||
|
public bool EnableMatrix { get; set; } = true;
|
||||||
|
public int SymbolCount { get; set; } = 25;
|
||||||
|
public bool EnableMatrixBackground { get; set; } = false;
|
||||||
|
public string MatrixChars { get; set; } = "0123456789";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OktoberfestOptions {
|
||||||
|
public bool EnableOktoberfest { get; set; } = true;
|
||||||
|
public int SymbolCount { get; set; } = 25;
|
||||||
|
public int SymbolCountMobile { get; set; } = 10;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OlympiaOptions {
|
||||||
|
public bool EnableOlympia { get; set; } = true;
|
||||||
|
public int SymbolCount { get; set; } = 25;
|
||||||
|
public int SymbolCountMobile { get; set; } = 10;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OscarOptions {
|
||||||
|
public bool EnableOscar { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PrideOptions {
|
||||||
|
public bool EnablePride { get; set; } = true;
|
||||||
|
public int HeartCount { get; set; } = 20;
|
||||||
|
public double HeartSize { get; set; } = 1.5;
|
||||||
|
public bool ColorHeader { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RainOptions {
|
||||||
|
public bool EnableRain { get; set; } = true;
|
||||||
|
public int RaindropCount { get; set; } = 300;
|
||||||
|
public int RaindropCountMobile { get; set; } = 150;
|
||||||
|
public double RainSpeed { get; set; } = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResurrectionOptions {
|
||||||
|
public bool EnableResurrection { get; set; } = true;
|
||||||
|
public int SymbolCount { get; set; } = 12;
|
||||||
|
public int SymbolCountMobile { get; set; } = 5;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SantaOptions {
|
||||||
|
public bool EnableSanta { get; set; } = true;
|
||||||
public int SnowflakesCount { get; set; } = 500;
|
public int SnowflakesCount { get; set; } = 500;
|
||||||
public int SnowflakesCountMobile { get; set; } = 250;
|
public int SnowflakesCountMobile { get; set; } = 250;
|
||||||
|
public double SnowFallSpeed { get; set; } = 3;
|
||||||
public double SantaSpeed { get; set; } = 10;
|
public double SantaSpeed { get; set; } = 10;
|
||||||
public double SantaSpeedMobile { get; set; } = 8;
|
public double SantaSpeedMobile { get; set; } = 8;
|
||||||
public bool EnableSanta { get; set; } = true;
|
|
||||||
public double SnowFallSpeed { get; set; } = 3;
|
|
||||||
public double MaxSantaRestTime { get; set; } = 8;
|
public double MaxSantaRestTime { get; set; } = 8;
|
||||||
public double MinSantaRestTime { get; set; } = 3;
|
public double MinSantaRestTime { get; set; } = 3;
|
||||||
public double MaxPresentFallSpeed { get; set; } = 5;
|
public double MaxPresentFallSpeed { get; set; } = 5;
|
||||||
public double MinPresentFallSpeed { get; set; } = 2;
|
public double MinPresentFallSpeed { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EasterOptions
|
public class SnowfallOptions {
|
||||||
{
|
public bool EnableSnowfall { get; set; } = true;
|
||||||
public int EggCount { get; set; } = 20;
|
public int SnowflakesCount { get; set; } = 500;
|
||||||
public bool EnableEaster { get; set; } = true;
|
public int SnowflakesCountMobile { get; set; } = 250;
|
||||||
public bool EnableRandomEaster { get; set; } = true;
|
public double Speed { get; set; } = 3;
|
||||||
public bool EnableRandomEasterMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
public bool EnableBunny { get; set; } = true;
|
|
||||||
public int BunnyDuration { get; set; } = 12000;
|
|
||||||
public int HopHeight { get; set; } = 12;
|
|
||||||
public int MinBunnyRestTime { get; set; } = 2000;
|
|
||||||
public int MaxBunnyRestTime { get; set; } = 5000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ResurrectionOptions
|
public class SnowflakesOptions {
|
||||||
{
|
public bool EnableSnowflakes { get; set; } = true;
|
||||||
public int SymbolCount { get; set; } = 12;
|
public int SnowflakeCount { get; set; } = 25;
|
||||||
public bool EnableResurrection { get; set; } = true;
|
public int SnowflakeCountMobile { get; set; } = 10;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
public bool EnableColoredSnowflakes { get; set; } = true;
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SpringOptions
|
public class SnowstormOptions {
|
||||||
{
|
public bool EnableSnowstorm { get; set; } = true;
|
||||||
public int PollenCount { get; set; } = 30;
|
public int SnowflakesCount { get; set; } = 500;
|
||||||
public int SunbeamCount { get; set; } = 5;
|
public int SnowflakesCountMobile { get; set; } = 250;
|
||||||
public int BirdCount { get; set; } = 4;
|
public double Speed { get; set; } = 6;
|
||||||
public int ButterflyCount { get; set; } = 4;
|
public double HorizontalWind { get; set; } = 4;
|
||||||
public int BeeCount { get; set; } = 2;
|
public double VerticalVariation { get; set; } = 2;
|
||||||
public int LadybugCount { get; set; } = 2;
|
}
|
||||||
public bool EnableSpring { get; set; } = true;
|
|
||||||
public bool EnableSpringSunbeams { get; set; } = true;
|
public class SpaceOptions {
|
||||||
public bool EnableRandomSpring { get; set; } = true;
|
public bool EnableSpace { get; set; } = true;
|
||||||
public bool EnableRandomSpringMobile { get; set; } = false;
|
public int PlanetCount { get; set; } = 6;
|
||||||
|
public int AstronautCount { get; set; } = 1;
|
||||||
|
public int SatelliteCount { get; set; } = 4;
|
||||||
|
public int IssCount { get; set; } = 1;
|
||||||
|
public int RocketCount { get; set; } = 1;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
public int SymbolCountMobile { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SummerOptions
|
public class SpookyOptions {
|
||||||
{
|
|
||||||
public int BubbleCount { get; set; } = 20;
|
|
||||||
public int DustCount { get; set; } = 50;
|
|
||||||
public bool EnableSummer { get; set; } = true;
|
|
||||||
public bool EnableRandomSummer { get; set; } = true;
|
|
||||||
public bool EnableRandomSummerMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CarnivalOptions
|
|
||||||
{
|
|
||||||
public int ObjectCount { get; set; } = 25;
|
|
||||||
public bool EnableCarnival { get; set; } = true;
|
|
||||||
public bool EnableRandomCarnival { get; set; } = true;
|
|
||||||
public bool EnableRandomCarnivalMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
public bool EnableCarnivalSway { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CherryBlossomOptions
|
|
||||||
{
|
|
||||||
public int PetalCount { get; set; } = 25;
|
|
||||||
public bool EnableCherryBlossom { get; set; } = true;
|
|
||||||
public bool EnableRandomCherryBlossom { get; set; } = true;
|
|
||||||
public bool EnableRandomCherryBlossomMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PiDayOptions
|
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 50;
|
|
||||||
public bool EnablePiDay { get; set; } = true;
|
|
||||||
public bool EnableRandomPiDay { get; set; } = true;
|
|
||||||
public bool EnableRandomPiDayMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
public bool EnablePiDayBackground { get; set; } = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EurovisionOptions
|
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
|
||||||
public bool EnableEurovision { get; set; } = true;
|
|
||||||
public bool EnableRandomEurovision { get; set; } = true;
|
|
||||||
public bool EnableRandomEurovisionMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
public bool EnableColorfulNotes { get; set; } = true;
|
|
||||||
public string EurovisionColors { get; set; } = "#ff0026ff,#17a6ffff,#32d432ff,#FFD700,#f0821bff,#f826f8ff";
|
|
||||||
public int EurovisionGlowSize { get; set; } = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StormOptions
|
|
||||||
{
|
|
||||||
public int RaindropCount { get; set; } = 300;
|
|
||||||
public int RaindropCountMobile { get; set; } = 150;
|
|
||||||
public bool EnableStorm { get; set; } = true;
|
|
||||||
public bool EnableLightning { get; set; } = true;
|
|
||||||
public double RainSpeed { get; set; } = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PrideOptions
|
|
||||||
{
|
|
||||||
public bool EnablePride { get; set; } = true;
|
|
||||||
public int HeartCount { get; set; } = 20;
|
|
||||||
public int HeartSize { get; set; } = 2;
|
|
||||||
public bool ColorHeader { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EarthDayOptions
|
|
||||||
{
|
|
||||||
public bool EnableEarthDay { get; set; } = true;
|
|
||||||
public int VineCount { get; set; } = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RainOptions
|
|
||||||
{
|
|
||||||
public bool EnableRain { get; set; } = true;
|
|
||||||
public int RaindropCount { get; set; } = 300;
|
|
||||||
public int RaindropCountMobile { get; set; } = 150;
|
|
||||||
public double RainSpeed { get; set; } = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FrostOptions
|
|
||||||
{
|
|
||||||
public bool EnableFrost { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FilmNoirOptions
|
|
||||||
{
|
|
||||||
public bool EnableFilmNoir { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OscarOptions
|
|
||||||
{
|
|
||||||
public bool EnableOscar { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MarioDayOptions
|
|
||||||
{
|
|
||||||
public bool EnableMarioDay { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StarWarsOptions
|
|
||||||
{
|
|
||||||
public bool EnableStarWars { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OktoberfestOptions
|
|
||||||
{
|
|
||||||
public bool EnableOktoberfest { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Friday13Options
|
|
||||||
{
|
|
||||||
public bool EnableFriday13 { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EidOptions
|
|
||||||
{
|
|
||||||
public bool EnableEid { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SpookyOptions
|
|
||||||
{
|
|
||||||
public bool EnableSpooky { get; set; } = true;
|
public bool EnableSpooky { get; set; } = true;
|
||||||
public int SymbolCount { get; set; } = 25;
|
public int SymbolCount { get; set; } = 25;
|
||||||
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
public bool EnableSpookySway { get; set; } = true;
|
public bool EnableSpookySway { get; set; } = true;
|
||||||
public int SpookySize { get; set; } = 20;
|
public int SpookySize { get; set; } = 20;
|
||||||
public int SpookyGlowSize { get; set; } = 2;
|
public int SpookyGlowSize { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SportsOptions
|
public class SportsOptions {
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
|
||||||
public bool EnableSports { get; set; } = true;
|
public bool EnableSports { get; set; } = true;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
public int SymbolCount { get; set; } = 5;
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
|
public string TurfColor { get; set; } = "#228b22";
|
||||||
|
public string SportsBalls { get; set; } = "football,basketball,tennis,volleyball";
|
||||||
|
public bool EnableTrophy { get; set; } = false;
|
||||||
|
public string ConfettiColors { get; set; } = "#000000,#FF0000,#FFCC00";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpringOptions {
|
||||||
|
public bool EnableSpring { get; set; } = true;
|
||||||
|
public int PollenCount { get; set; } = 30;
|
||||||
|
public bool EnableSpringSunbeams { get; set; } = true;
|
||||||
|
public int SunbeamCount { get; set; } = 5;
|
||||||
|
public int BirdCount { get; set; } = 3;
|
||||||
|
public int ButterflyCount { get; set; } = 4;
|
||||||
|
public int BeeCount { get; set; } = 2;
|
||||||
|
public int LadybugCount { get; set; } = 2;
|
||||||
|
public int SymbolCountMobile { get; set; } = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StarWarsOptions {
|
||||||
|
public bool EnableStarWars { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StormOptions {
|
||||||
|
public bool EnableStorm { get; set; } = true;
|
||||||
|
public int RaindropCount { get; set; } = 300;
|
||||||
|
public int RaindropCountMobile { get; set; } = 150;
|
||||||
|
public bool EnableLightning { get; set; } = true;
|
||||||
|
public double RainSpeed { get; set; } = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SummerOptions {
|
||||||
|
public bool EnableSummer { get; set; } = true;
|
||||||
|
public int BubbleCount { get; set; } = 30;
|
||||||
|
public int DustCount { get; set; } = 50;
|
||||||
|
public int SymbolCountMobile { get; set; } = 2;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OlympiaOptions
|
public class UnderwaterOptions {
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
|
||||||
public bool EnableOlympia { get; set; } = true;
|
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SpaceOptions
|
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 25;
|
|
||||||
public bool EnableSpace { get; set; } = true;
|
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UnderwaterOptions
|
|
||||||
{
|
|
||||||
public int SymbolCount { get; set; } = 15;
|
|
||||||
public bool EnableUnderwater { get; set; } = true;
|
public bool EnableUnderwater { get; set; } = true;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
public int SymbolCountMobile { get; set; } = 2;
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public bool EnableDifferentDuration { get; set; } = true;
|
||||||
}
|
public bool EnableLightRays { get; set; } = true;
|
||||||
|
public int SeaweedCount { get; set; } = 50;
|
||||||
public class BirthdayOptions
|
public int CrabCount { get; set; } = 2;
|
||||||
{
|
public int StarfishCount { get; set; } = 2;
|
||||||
public int SymbolCount { get; set; } = 25;
|
public int ShellCount { get; set; } = 2;
|
||||||
public bool EnableBirthday { get; set; } = true;
|
public int FishCount { get; set; } = 15;
|
||||||
public bool EnableRandomSymbols { get; set; } = true;
|
public int SeahorseCount { get; set; } = 3;
|
||||||
public bool EnableRandomSymbolsMobile { get; set; } = false;
|
public int JellyfishCount { get; set; } = 3;
|
||||||
public bool EnableDifferentDuration { get; set; } = true;
|
public int TurtleCount { get; set; } = 1;
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
|
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
|
||||||
<Title>Jellyfin Seasonals Plugin</Title>
|
<Title>Jellyfin Seasonals Plugin</Title>
|
||||||
<Authors>CodeDevMLH</Authors>
|
<Authors>CodeDevMLH</Authors>
|
||||||
<Version>1.7.2.0</Version>
|
<Version>2.0.0.8</Version>
|
||||||
<RepositoryUrl>https://github.com/CodeDevMLH/Jellyfin-Seasonals</RepositoryUrl>
|
<RepositoryUrl>https://github.com/CodeDevMLH/Jellyfin-Seasonals</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,7 @@
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
text-shadow: 0 0 5px #000;
|
text-shadow: 0 0 5px #000;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
-webkit-animation-name: leaf-fall, leaf-shake;
|
|
||||||
-webkit-animation-duration: 7s, 4s;
|
|
||||||
-webkit-animation-timing-function: linear, ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite, infinite;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
animation-name: leaf-fall, leaf-shake;
|
animation-name: leaf-fall, leaf-shake;
|
||||||
animation-duration: 7s, 4s;
|
animation-duration: 7s, 4s;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
@@ -41,15 +35,6 @@
|
|||||||
--rotate-end: 0deg !important;
|
--rotate-end: 0deg !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes leaf-fall {
|
|
||||||
0% {
|
|
||||||
translate: 0 -10vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
translate: 0 100vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes leaf-fall {
|
@keyframes leaf-fall {
|
||||||
0% {
|
0% {
|
||||||
@@ -61,14 +46,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes leaf-shake {
|
|
||||||
0%, 100% {
|
|
||||||
transform: translateX(0) rotate(var(--rotate-start, -20deg));
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: translateX(80px) rotate(var(--rotate-end, 20deg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes leaf-shake {
|
@keyframes leaf-shake {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
@@ -78,87 +55,3 @@
|
|||||||
transform: translateX(80px) rotate(var(--rotate-end, 20deg));
|
transform: translateX(80px) rotate(var(--rotate-end, 20deg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.leaf:nth-of-type(0) {
|
|
||||||
left: 0%;
|
|
||||||
animation-delay: 0s, 0s;
|
|
||||||
--rotate-start: -25deg;
|
|
||||||
--rotate-end: 22deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(1) {
|
|
||||||
left: 10%;
|
|
||||||
animation-delay: 1s, 0.5s;
|
|
||||||
--rotate-start: -32deg;
|
|
||||||
--rotate-end: 35deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(2) {
|
|
||||||
left: 20%;
|
|
||||||
animation-delay: 6s, 1s;
|
|
||||||
--rotate-start: -28deg;
|
|
||||||
--rotate-end: 28deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(3) {
|
|
||||||
left: 30%;
|
|
||||||
animation-delay: 4s, 1.5s;
|
|
||||||
--rotate-start: -38deg;
|
|
||||||
--rotate-end: 32deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(4) {
|
|
||||||
left: 40%;
|
|
||||||
animation-delay: 2s, 0.8s;
|
|
||||||
--rotate-start: -22deg;
|
|
||||||
--rotate-end: 38deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(5) {
|
|
||||||
left: 50%;
|
|
||||||
animation-delay: 8s, 2s;
|
|
||||||
--rotate-start: -35deg;
|
|
||||||
--rotate-end: 25deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(6) {
|
|
||||||
left: 60%;
|
|
||||||
animation-delay: 6s, 1.2s;
|
|
||||||
--rotate-start: -40deg;
|
|
||||||
--rotate-end: 40deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(7) {
|
|
||||||
left: 70%;
|
|
||||||
animation-delay: 2.5s, 0.3s;
|
|
||||||
--rotate-start: -30deg;
|
|
||||||
--rotate-end: 30deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(8) {
|
|
||||||
left: 80%;
|
|
||||||
animation-delay: 1s, 1.8s;
|
|
||||||
--rotate-start: -26deg;
|
|
||||||
--rotate-end: 36deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(9) {
|
|
||||||
left: 90%;
|
|
||||||
animation-delay: 3s, 0.7s;
|
|
||||||
--rotate-start: -34deg;
|
|
||||||
--rotate-end: 24deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(10) {
|
|
||||||
left: 25%;
|
|
||||||
animation-delay: 2s, 2.3s;
|
|
||||||
--rotate-start: -29deg;
|
|
||||||
--rotate-end: 33deg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaf:nth-of-type(11) {
|
|
||||||
left: 65%;
|
|
||||||
animation-delay: 4s, 1.4s;
|
|
||||||
--rotate-start: -37deg;
|
|
||||||
--rotate-end: 27deg;
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Autumn || {};
|
const config = window.SeasonalsPluginConfig?.Autumn || {};
|
||||||
|
|
||||||
const leaves = config.EnableAutumn !== undefined ? config.EnableAutumn : true; // enable/disable leaves
|
const leaves = config.EnableAutumn !== undefined ? config.EnableAutumn : true; // enable/disable autumn
|
||||||
const randomLeaves = config.EnableRandomLeaves !== undefined ? config.EnableRandomLeaves : true; // enable random leaves
|
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const randomLeavesMobile = config.EnableRandomLeavesMobile !== undefined ? config.EnableRandomLeavesMobile : false; // enable random leaves on mobile devices (Warning: High values may affect performance)
|
const enableRotation = config.EnableRotation !== undefined ? config.EnableRotation : false; // enable/disable rotation
|
||||||
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different duration for the random leaves
|
const leafCount = config.LeafCount !== undefined ? config.LeafCount : 35; // count of random extra leaves
|
||||||
const enableRotation = config.EnableRotation !== undefined ? config.EnableRotation : false; // enable/disable leaf rotation
|
const leafCountMobile = config.LeafCountMobile !== undefined ? config.LeafCountMobile : 10; // count of random extra leaves on mobile
|
||||||
const leafCount = config.LeafCount || 25; // count of random extra leaves
|
|
||||||
|
|
||||||
const images = [
|
const images = [
|
||||||
"../Seasonals/Resources/autumn_images/acorn1.png",
|
"../Seasonals/Resources/autumn_images/acorn1.png",
|
||||||
@@ -64,11 +63,16 @@ observer.observe(document.body, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function addRandomLeaves(count) {
|
function initLeaves(count) {
|
||||||
const autumnContainer = document.querySelector('.autumn-container'); // get the leave container
|
let autumnContainer = document.querySelector('.autumn-container'); // get the leave container
|
||||||
if (!autumnContainer) return; // exit if leave container is not found
|
if (!autumnContainer) {
|
||||||
|
autumnContainer = document.createElement("div");
|
||||||
|
autumnContainer.className = "autumn-container";
|
||||||
|
autumnContainer.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(autumnContainer);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Adding random leaves');
|
console.log('Adding leaves');
|
||||||
|
|
||||||
// Array of leave characters
|
// Array of leave characters
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
@@ -87,6 +91,8 @@ function addRandomLeaves(count) {
|
|||||||
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
||||||
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
||||||
const randomAnimationDelay = Math.random() * 12; // delay for fall (0s to 12s)
|
const randomAnimationDelay = Math.random() * 12; // delay for fall (0s to 12s)
|
||||||
|
// Display directly symbols on full screen (below) or let it build up (above)
|
||||||
|
// const randomAnimationDelay = -(Math.random() * 16); // delay for fall (-16s to 0s)
|
||||||
const randomAnimationDelay2 = -(Math.random() * 4); // delay for shake+rotate (-4s to 0s)
|
const randomAnimationDelay2 = -(Math.random() * 4); // delay for shake+rotate (-4s to 0s)
|
||||||
|
|
||||||
// apply styles
|
// apply styles
|
||||||
@@ -115,60 +121,18 @@ function addRandomLeaves(count) {
|
|||||||
// add the leave to the container
|
// add the leave to the container
|
||||||
autumnContainer.appendChild(leaveDiv);
|
autumnContainer.appendChild(leaveDiv);
|
||||||
}
|
}
|
||||||
console.log('Random leaves added');
|
console.log('Leaves added');
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize standard leaves
|
// initialize leaves
|
||||||
function initLeaves() {
|
|
||||||
const container = document.querySelector('.autumn-container') || document.createElement("div");
|
|
||||||
|
|
||||||
if (!document.querySelector('.autumn-container')) {
|
|
||||||
container.className = "autumn-container";
|
|
||||||
container.setAttribute("aria-hidden", "true");
|
|
||||||
document.body.appendChild(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < 12; i++) {
|
|
||||||
const leafDiv = document.createElement("div");
|
|
||||||
leafDiv.className = enableRotation ? "leaf" : "leaf no-rotation";
|
|
||||||
|
|
||||||
const img = document.createElement("img");
|
|
||||||
img.src = images[Math.floor(Math.random() * images.length)];
|
|
||||||
|
|
||||||
// set random animation duration
|
|
||||||
if (enableDiffrentDuration) {
|
|
||||||
const randomAnimationDuration = Math.random() * 10 + 6; // fall duration (6s to 16s)
|
|
||||||
const randomAnimationDuration2 = Math.random() * 3 + 2; // shake+rotate duration (2s to 5s)
|
|
||||||
leafDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set random rotation angles for standard leaves too (only if rotation is enabled)
|
|
||||||
if (enableRotation) {
|
|
||||||
const randomRotateStart = -(Math.random() * 40 + 20); // -20deg to -60deg
|
|
||||||
const randomRotateEnd = Math.random() * 40 + 20; // 20deg to 60deg
|
|
||||||
leafDiv.style.setProperty('--rotate-start', `${randomRotateStart}deg`);
|
|
||||||
leafDiv.style.setProperty('--rotate-end', `${randomRotateEnd}deg`);
|
|
||||||
} else {
|
|
||||||
// No rotation - set to 0 degrees
|
|
||||||
leafDiv.style.setProperty('--rotate-start', '0deg');
|
|
||||||
leafDiv.style.setProperty('--rotate-end', '0deg');
|
|
||||||
}
|
|
||||||
|
|
||||||
leafDiv.appendChild(img);
|
|
||||||
container.appendChild(leafDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize leaves and add random leaves
|
|
||||||
function initializeLeaves() {
|
function initializeLeaves() {
|
||||||
if (!leaves) return; // exit if leaves are disabled
|
if (!leaves) return; // exit if leaves are disabled
|
||||||
initLeaves();
|
|
||||||
toggleAutumn();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomLeaves && (screenWidth > 768 || randomLeavesMobile)) { // add random leaves only on larger screens, unless enabled for mobile devices
|
const count = !isMobile ? leafCount : leafCountMobile;
|
||||||
addRandomLeaves(leafCount);
|
|
||||||
}
|
initLeaves(count);
|
||||||
|
toggleAutumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeLeaves();
|
initializeLeaves();
|
||||||
@@ -5,86 +5,151 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 9999;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
}
|
contain: layout paint;
|
||||||
|
|
||||||
.birthday-cake {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 2vh;
|
|
||||||
left: 50vw;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
font-size: 8rem;
|
|
||||||
z-index: 50;
|
|
||||||
filter: drop-shadow(0 0 10px rgba(255,255,255,0.4));
|
|
||||||
}
|
|
||||||
|
|
||||||
.birthday-cake img {
|
|
||||||
height: 15vh;
|
|
||||||
width: auto;
|
|
||||||
object-fit: contain;
|
|
||||||
max-height: 150px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.birthday-symbol {
|
.birthday-symbol {
|
||||||
position: absolute;
|
will-change: opacity;
|
||||||
bottom: -10vh; /* balloons rise from bottom */
|
position: fixed;
|
||||||
animation: birthday-rise linear infinite;
|
top: 0;
|
||||||
font-size: 3rem;
|
left: 0;
|
||||||
|
animation: birthday-rise linear infinite forwards;
|
||||||
opacity: 0.95;
|
opacity: 0.95;
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.birthday-sway {
|
||||||
|
will-change: transform;
|
||||||
|
animation-name: birthday-sway;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-inner {
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: crosshair;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MARK: Balloon Size */
|
||||||
.birthday-symbol img {
|
.birthday-symbol img {
|
||||||
width: 6vh;
|
width: 18vh;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-width: 60px;
|
max-width: 100px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.birthday-confetti-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 30;
|
||||||
|
will-change: transform;
|
||||||
|
animation-name: birthday-confetti-fall;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.birthday-confetti {
|
.birthday-confetti {
|
||||||
position: absolute;
|
width: 8px;
|
||||||
top: -5vh;
|
height: 16px;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
will-change: transform;
|
||||||
|
animation-name: birthday-flutter;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-confetti.circle {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-confetti.square {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-confetti.triangle {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
opacity: 0.9;
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
||||||
animation: birthday-confetti-fall linear infinite;
|
|
||||||
z-index: 30;
|
|
||||||
/* Mix of circles and squares by using CSS variables or random in JS. For simplicity, we make all slightly rounded rectangles */
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes birthday-rise {
|
@keyframes birthday-rise {
|
||||||
0% {
|
0% { transform: translate3d(var(--x-pos, 0vw), 110vh, 0) rotate(var(--start-rot, 0deg)); opacity: 0; }
|
||||||
transform: translateY(10vh) rotate(var(--start-rot, 0deg));
|
10% { opacity: 1; }
|
||||||
opacity: 0;
|
90% { opacity: 1; }
|
||||||
}
|
100% { transform: translate3d(var(--x-pos, 0vw), -20vh, 0) rotate(calc(var(--start-rot, 0deg) * -1)); opacity: 0; }
|
||||||
10% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(-110vh) rotate(calc(var(--start-rot, 0deg) * -1));
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes birthday-confetti-fall {
|
@keyframes birthday-confetti-fall {
|
||||||
|
0% { transform: translate3d(var(--x-pos, 0vw), -10vh, 0); }
|
||||||
|
100% { transform: translate3d(var(--x-pos, 0vw), 110vh, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes birthday-sway {
|
||||||
|
0% { transform: translateX(calc(var(--sway-amount, 50px) * -1)); }
|
||||||
|
100% { transform: translateX(var(--sway-amount, 50px)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes birthday-flutter {
|
||||||
|
0% { transform: rotate3d(var(--rx, 1), var(--ry, 1), var(--rz, 0), 0deg); }
|
||||||
|
100% { transform: rotate3d(var(--rx, 1), var(--ry, 1), var(--rz, 0), var(--rot-dir, 360deg)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes birthday-pop {
|
||||||
|
0% { transform: scale(1); opacity: 1; filter: brightness(1); }
|
||||||
|
30% { transform: scale(1.3); opacity: 1; filter: brightness(1.5); }
|
||||||
|
100% { transform: scale(0); opacity: 0; filter: brightness(2); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-burst-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1000;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
animation: birthday-burst-y 1.2s cubic-bezier(0.42, 0, 1, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-burst-confetti {
|
||||||
|
will-change: transform;
|
||||||
|
animation: birthday-burst-x 1.2s cubic-bezier(0.25, 1, 0.5, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-burst-confetti.circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birthday-burst-confetti.triangle {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes birthday-burst-y {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(-5vh) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
|
transform: translateY(0);
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
5% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(105vh) rotateX(720deg) rotateY(360deg) rotateZ(180deg);
|
transform: translateY(calc(var(--burst-y) + 150px));
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes birthday-burst-x {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0) rotate3d(var(--rx), var(--ry), var(--rz), 0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(calc(var(--burst-x) * 1.5)) rotate3d(var(--rx), var(--ry), var(--rz), var(--rot-dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,39 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Birthday || {};
|
const config = window.SeasonalsPluginConfig?.Birthday || {};
|
||||||
|
|
||||||
const birthday = config.EnableBirthday !== undefined ? config.EnableBirthday : true;
|
const birthday = config.EnableBirthday !== undefined ? config.EnableBirthday : true; // enable/disable birthday symbols
|
||||||
const symbolCount = config.SymbolCount || 25;
|
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 12; // count of balloons
|
||||||
const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different duration for the symbols
|
||||||
const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 5; // count of mobile balloons
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const baseConfettiCount = config.ConfettiCount !== undefined ? config.ConfettiCount : 60; // count of confetti
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base ballon image: https://www.flaticon.com/de/kostenloses-icon/ballon_1512470
|
||||||
|
* modified by CodeDevMLH
|
||||||
|
*/
|
||||||
|
const birthdayImages = [
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_blue.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_green.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_lightblue.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_orange.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_pink.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_red.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_yellow.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_turquoise.gif',
|
||||||
|
'../Seasonals/Resources/birthday_assets/balloon_violet.gif'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const balloonColors = {
|
||||||
|
'balloon_blue': ['#3498db', '#2980b9', '#1f618d'],
|
||||||
|
'balloon_green': ['#2ecc71', '#27ae60', '#1e8449'],
|
||||||
|
'balloon_lightblue': ['#36c5f0', '#81ecec', '#00cec9'],
|
||||||
|
'balloon_orange': ['#e67e22', '#d35400', '#a04000'],
|
||||||
|
'balloon_pink': ['#ff726d', '#f4306d', '#e84393'],
|
||||||
|
'balloon_red': ['#e74c3c', '#c0392b', '#922b21'],
|
||||||
|
'balloon_yellow': ['#f1c40f', '#f39c12', '#b7950b'],
|
||||||
|
'balloon_turquoise': ['#36c5f0', '#81ecec', '#00cec9'],
|
||||||
|
'balloon_violet': ['#9b59b6', '#8e44ad', '#6c3483']
|
||||||
|
};
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -39,6 +68,72 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function createBalloonPopConfetti(container, x, y, colors) {
|
||||||
|
const popConfettiColors = colors || [
|
||||||
|
'#fce18a', '#ff726d', '#b48def', '#f4306d',
|
||||||
|
'#36c5f0', '#2ccc5d', '#e9b31d', '#9b59b6',
|
||||||
|
'#3498db', '#e74c3c', '#1abc9c', '#f1c40f'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Spawn 15-20 particles
|
||||||
|
const particleCount = Math.floor(Math.random() * 5) + 15;
|
||||||
|
|
||||||
|
for (let i = 0; i < particleCount; i++) {
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'birthday-burst-wrapper';
|
||||||
|
wrapper.style.position = 'absolute';
|
||||||
|
wrapper.style.left = `${x}px`;
|
||||||
|
wrapper.style.top = `${y}px`;
|
||||||
|
wrapper.style.zIndex = '1000';
|
||||||
|
|
||||||
|
const particle = document.createElement('div');
|
||||||
|
particle.classList.add('birthday-burst-confetti');
|
||||||
|
|
||||||
|
// Random color
|
||||||
|
const color = popConfettiColors[Math.floor(Math.random() * popConfettiColors.length)];
|
||||||
|
particle.style.backgroundColor = color;
|
||||||
|
|
||||||
|
// Random shape
|
||||||
|
const shape = Math.random();
|
||||||
|
if (shape > 0.66) {
|
||||||
|
particle.classList.add('circle');
|
||||||
|
const size = Math.random() * 4 + 4; // 4-8px
|
||||||
|
particle.style.width = `${size}px`;
|
||||||
|
particle.style.height = `${size}px`;
|
||||||
|
} else if (shape > 0.33) {
|
||||||
|
particle.classList.add('rect');
|
||||||
|
const width = Math.random() * 3 + 3; // 3-6px
|
||||||
|
const height = Math.random() * 4 + 6; // 6-10px
|
||||||
|
particle.style.width = `${width}px`;
|
||||||
|
particle.style.height = `${height}px`;
|
||||||
|
} else {
|
||||||
|
particle.classList.add('triangle');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random direction for explosion (circular)
|
||||||
|
const angle = Math.random() * 2 * Math.PI;
|
||||||
|
const distance = Math.random() * 60 + 20; // 20-80px burst radius
|
||||||
|
|
||||||
|
const xOffset = Math.cos(angle) * distance;
|
||||||
|
const yOffset = Math.sin(angle) * distance;
|
||||||
|
|
||||||
|
particle.style.setProperty('--burst-x', `${xOffset}px`);
|
||||||
|
wrapper.style.setProperty('--burst-y', `${yOffset}px`);
|
||||||
|
|
||||||
|
// Random rotation during fall
|
||||||
|
particle.style.setProperty('--rot-dir', `${(Math.random() > 0.5 ? 1 : -1) * 360}deg`);
|
||||||
|
particle.style.setProperty('--rx', Math.random().toFixed(2));
|
||||||
|
particle.style.setProperty('--ry', Math.random().toFixed(2));
|
||||||
|
particle.style.setProperty('--rz', (Math.random() * 0.5).toFixed(2));
|
||||||
|
|
||||||
|
wrapper.appendChild(particle);
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
// Remove particle after animation
|
||||||
|
setTimeout(() => wrapper.remove(), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createBirthday() {
|
function createBirthday() {
|
||||||
const container = document.querySelector('.birthday-container') || document.createElement('div');
|
const container = document.querySelector('.birthday-container') || document.createElement('div');
|
||||||
|
|
||||||
@@ -48,59 +143,106 @@ function createBirthday() {
|
|||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn Birthday Cake at the bottom
|
// Cake and Garland have been removed
|
||||||
const cake = document.createElement('div');
|
|
||||||
cake.className = 'birthday-cake';
|
|
||||||
let cakeImg = document.createElement('img');
|
|
||||||
cakeImg.src = `../Seasonals/Resources/birthday_images/cake.png`;
|
|
||||||
cakeImg.onerror = function() {
|
|
||||||
this.style.display = 'none';
|
|
||||||
this.parentElement.innerHTML = '🎂';
|
|
||||||
};
|
|
||||||
cake.appendChild(cakeImg);
|
|
||||||
container.appendChild(cake);
|
|
||||||
|
|
||||||
const standardCount = 15;
|
|
||||||
const totalSymbols = symbolCount + standardCount;
|
|
||||||
|
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
let finalCount = totalSymbols;
|
let finalCount = isMobile ? symbolCountMobile : symbolCount;
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
finalCount = enableRandomMobile ? totalSymbols : standardCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useRandomDuration = enableDifferentDuration !== false;
|
const useRandomDuration = enableDifferentDuration !== false;
|
||||||
|
|
||||||
// We'll treat balloons and gifts as rising symbols
|
// Arrays moved to top of file
|
||||||
const activeItems = ['balloon_red', 'balloon_blue', 'balloon_yellow', 'gift'];
|
|
||||||
|
|
||||||
for (let i = 0; i < finalCount; i++) {
|
for (let i = 0; i < finalCount; i++) {
|
||||||
let symbol = document.createElement('div');
|
let symbol = document.createElement('div');
|
||||||
|
|
||||||
const randomItem = activeItems[Math.floor(Math.random() * activeItems.length)];
|
const randomImage = birthdayImages[Math.floor(Math.random() * birthdayImages.length)];
|
||||||
|
const randomItem = randomImage.split('/').pop().split('.')[0]; // Extracts "balloon_blue"
|
||||||
symbol.className = `birthday-symbol birthday-${randomItem}`;
|
symbol.className = `birthday-symbol birthday-${randomItem}`;
|
||||||
|
|
||||||
|
// Create inner div for sway
|
||||||
|
let innerDiv = document.createElement('div');
|
||||||
|
innerDiv.className = 'birthday-inner';
|
||||||
|
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = `../Seasonals/Resources/birthday_images/${randomItem}.png`;
|
img.src = randomImage;
|
||||||
img.onerror = function() {
|
img.onerror = function() {
|
||||||
this.style.display = 'none';
|
symbol.remove(); // Remove element completely on error
|
||||||
this.parentElement.innerHTML = getBirthdayEmojiFallback(randomItem);
|
|
||||||
};
|
};
|
||||||
symbol.appendChild(img);
|
innerDiv.appendChild(img);
|
||||||
|
|
||||||
|
// Sway wrapper
|
||||||
|
let swayWrapper = document.createElement('div');
|
||||||
|
swayWrapper.className = 'birthday-sway';
|
||||||
|
const swayDuration = Math.random() * 3 + 3; // 3-6s per cycle
|
||||||
|
swayWrapper.style.animationDuration = `${swayDuration}s`;
|
||||||
|
swayWrapper.style.animationDelay = `-${Math.random() * 5}s`;
|
||||||
|
const swayAmount = Math.random() * 60 + 20; // 20-80px
|
||||||
|
const direction = Math.random() > 0.5 ? 1 : -1;
|
||||||
|
swayWrapper.style.setProperty('--sway-amount', `${swayAmount * direction}px`);
|
||||||
|
|
||||||
|
swayWrapper.appendChild(innerDiv);
|
||||||
|
symbol.appendChild(swayWrapper);
|
||||||
|
|
||||||
const leftPos = Math.random() * 95;
|
const leftPos = Math.random() * 95;
|
||||||
const delaySeconds = Math.random() * 10;
|
|
||||||
|
|
||||||
|
// Far away effect
|
||||||
|
const depth = Math.random();
|
||||||
|
// MARK: balloon size
|
||||||
|
const scale = 0.85 + depth * 0.3; // 0.85 to 1.15
|
||||||
|
const zIndex = Math.floor(depth * 30) + 10;
|
||||||
|
|
||||||
|
img.style.transform = `scale(${scale})`;
|
||||||
|
symbol.style.zIndex = zIndex;
|
||||||
|
|
||||||
let durationSeconds = 9;
|
let durationSeconds = 9;
|
||||||
if (useRandomDuration) {
|
if (useRandomDuration) {
|
||||||
durationSeconds = Math.random() * 5 + 7; // 7 to 12 seconds
|
// Far strings climb slower
|
||||||
|
durationSeconds = (1 - depth) * 6 + 7 + Math.random() * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative delay correctly scatters them initially across the screen vertically
|
||||||
|
// avoiding them all popping up at bottom edge together
|
||||||
|
const delaySeconds = -(Math.random() * durationSeconds);
|
||||||
|
|
||||||
|
const isBalloon = randomItem.startsWith('balloon');
|
||||||
|
|
||||||
|
if (isBalloon) {
|
||||||
|
// Sway animation is now handled natively by the GIF motion.
|
||||||
|
|
||||||
|
// Interaction to pop is handled visually by the GIF, but we can still remove it on hover
|
||||||
|
innerDiv.addEventListener('mouseenter', function(e) {
|
||||||
|
if (!this.classList.contains('popped')) {
|
||||||
|
this.classList.add('popped');
|
||||||
|
this.style.animation = 'birthday-pop 0.2s ease-out forwards';
|
||||||
|
this.style.pointerEvents = 'none'; // avoid re-triggering
|
||||||
|
|
||||||
|
// Create confetti burst at balloon's screen position
|
||||||
|
const rect = this.getBoundingClientRect();
|
||||||
|
const cx = rect.left + rect.width / 2;
|
||||||
|
// explosion height
|
||||||
|
const cy = rect.top + rect.height * -0.05;
|
||||||
|
// Ensure the burst container is appended to the main document body or the birthday container
|
||||||
|
createBalloonPopConfetti(document.body, cx, cy, balloonColors[randomItem]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset the balloon when it reappears at the bottom of the screen
|
||||||
|
symbol.addEventListener('animationiteration', function(e) {
|
||||||
|
// Ignore bubbling events from the inner sway animation
|
||||||
|
if (e.animationName === 'birthday-rise' || e.target === symbol) {
|
||||||
|
if (innerDiv.classList.contains('popped')) {
|
||||||
|
innerDiv.classList.remove('popped');
|
||||||
|
innerDiv.style.animation = '';
|
||||||
|
innerDiv.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const startRot = (Math.random() * 20) - 10; // -10 to +10 spread
|
const startRot = (Math.random() * 20) - 10; // -10 to +10 spread
|
||||||
symbol.style.setProperty('--start-rot', `${startRot}deg`);
|
symbol.style.setProperty('--start-rot', `${startRot}deg`);
|
||||||
|
symbol.style.setProperty('--x-pos', `${leftPos}vw`);
|
||||||
|
|
||||||
symbol.style.left = `${leftPos}vw`;
|
|
||||||
symbol.style.animationDuration = `${durationSeconds}s`;
|
symbol.style.animationDuration = `${durationSeconds}s`;
|
||||||
symbol.style.animationDelay = `${delaySeconds}s`;
|
symbol.style.animationDelay = `${delaySeconds}s`;
|
||||||
|
|
||||||
@@ -108,33 +250,72 @@ function createBirthday() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Party Confetti
|
// Party Confetti
|
||||||
const confettiColors = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000'];
|
const confettiCount = baseConfettiCount;
|
||||||
const confettiCount = isMobile ? 40 : 80;
|
const allColors = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000'];
|
||||||
|
|
||||||
for (let i = 0; i < confettiCount; i++) {
|
for (let i = 0; i < confettiCount; i++) {
|
||||||
let confetti = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
confetti.className = 'birthday-confetti';
|
wrapper.classList.add('birthday-confetti-wrapper');
|
||||||
|
|
||||||
const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
|
// Use carnival.js 3D advanced fluttering logic
|
||||||
|
let swayWrapper = document.createElement('div');
|
||||||
|
swayWrapper.classList.add('birthday-sway');
|
||||||
|
wrapper.appendChild(swayWrapper);
|
||||||
|
|
||||||
|
const confetti = document.createElement('div');
|
||||||
|
confetti.classList.add('birthday-confetti');
|
||||||
|
|
||||||
|
const color = allColors[Math.floor(Math.random() * allColors.length)];
|
||||||
confetti.style.backgroundColor = color;
|
confetti.style.backgroundColor = color;
|
||||||
|
|
||||||
|
// Shape assignments
|
||||||
|
const shape = Math.random();
|
||||||
|
if (shape > 0.8) confetti.classList.add('circle');
|
||||||
|
else if (shape > 0.6) confetti.classList.add('square');
|
||||||
|
else if (shape > 0.4) confetti.classList.add('triangle');
|
||||||
|
else confetti.classList.add('rect'); // default
|
||||||
|
|
||||||
|
// Sizing
|
||||||
|
if (!confetti.classList.contains('circle') && !confetti.classList.contains('square') && !confetti.classList.contains('triangle')) {
|
||||||
|
const width = Math.random() * 3 + 4; // 4-7px
|
||||||
|
const height = Math.random() * 5 + 8; // 8-13px
|
||||||
|
confetti.style.width = `${width}px`;
|
||||||
|
confetti.style.height = `${height}px`;
|
||||||
|
} else if (confetti.classList.contains('circle') || confetti.classList.contains('square')) {
|
||||||
|
const size = Math.random() * 5 + 5; // 5-10px
|
||||||
|
confetti.style.width = `${size}px`;
|
||||||
|
confetti.style.height = `${size}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration = Math.random() * 5 + 5;
|
||||||
|
const delay = -Math.random() * duration; // Spawn fully integrated across screen width/height
|
||||||
|
|
||||||
const leftPos = Math.random() * 100;
|
wrapper.style.setProperty('--x-pos', `${Math.random() * 100}vw`);
|
||||||
const delaySeconds = Math.random() * 8;
|
wrapper.style.animationDelay = `${delay}s`;
|
||||||
const duration = Math.random() * 3 + 4;
|
wrapper.style.animationDuration = `${duration}s`;
|
||||||
|
|
||||||
|
// Sway handling
|
||||||
|
const swayDuration = Math.random() * 2 + 3; // 3-5s per cycle
|
||||||
|
swayWrapper.style.animationDuration = `${swayDuration}s`;
|
||||||
|
swayWrapper.style.animationDelay = `-${Math.random() * 5}s`;
|
||||||
|
const swayAmount = Math.random() * 70 + 30; // 30-100px
|
||||||
|
const direction = Math.random() > 0.5 ? 1 : -1;
|
||||||
|
swayWrapper.style.setProperty('--sway-amount', `${swayAmount * direction}px`);
|
||||||
|
|
||||||
|
// 3D Flutter Rotation
|
||||||
|
confetti.style.animationDuration = `${Math.random() * 2 + 1}s`;
|
||||||
|
confetti.style.setProperty('--rx', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--ry', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--rz', (Math.random() * 0.5).toFixed(2));
|
||||||
|
const rotDir = Math.random() > 0.5 ? 1 : -1;
|
||||||
|
confetti.style.setProperty('--rot-dir', `${rotDir * 360}deg`);
|
||||||
|
|
||||||
confetti.style.left = `${leftPos}vw`;
|
swayWrapper.appendChild(confetti);
|
||||||
confetti.style.animationDuration = `${duration}s`;
|
container.appendChild(wrapper);
|
||||||
confetti.style.animationDelay = `${delaySeconds}s`;
|
|
||||||
|
|
||||||
container.appendChild(confetti);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBirthdayEmojiFallback(type) {
|
/* Removed fallback logic */
|
||||||
if (type.startsWith('balloon')) return '🎈';
|
|
||||||
if (type === 'gift') return '🎁';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeBirthday() {
|
function initializeBirthday() {
|
||||||
if (!birthday) return;
|
if (!birthday) return;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
BIN
Jellyfin.Plugin.Seasonals/Web/birthday_assets/balloon_violet.gif
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 108 KiB |
@@ -1,11 +1,10 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Carnival || {};
|
const config = window.SeasonalsPluginConfig?.Carnival || {};
|
||||||
|
|
||||||
const carnival = config.EnableCarnival !== undefined ? config.EnableCarnival : true; // Enable/disable carnival
|
const carnival = config.EnableCarnival !== undefined ? config.EnableCarnival : true; // enable/disable carnival
|
||||||
const randomCarnival = config.EnableRandomCarnival !== undefined ? config.EnableRandomCarnival : true; // Enable random carnival objects
|
const carnivalCount = config.ObjectCount !== undefined ? config.ObjectCount : 120; // Number of confetti pieces to spawn
|
||||||
const randomCarnivalMobile = config.EnableRandomCarnivalMobile !== undefined ? config.EnableRandomCarnivalMobile : false; // Enable random carnival objects on mobile
|
const carnivalCountMobile = config.ObjectCountMobile !== undefined ? config.ObjectCountMobile : 60; // Number of confetti pieces to spawn on mobile
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // Randomize falling and flutter speeds
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableSway = config.EnableCarnivalSway !== undefined ? config.EnableCarnivalSway : true; // Enable side-to-side sway animation
|
const enableSway = config.EnableCarnivalSway !== undefined ? config.EnableCarnivalSway : true; // enable/disable carnivalsway
|
||||||
const carnivalCount = config.ObjectCount || 120; // Number of confetti pieces to spawn
|
|
||||||
|
|
||||||
const confettiColors = [
|
const confettiColors = [
|
||||||
'#fce18a', '#ff726d', '#b48def', '#f4306d',
|
'#fce18a', '#ff726d', '#b48def', '#f4306d',
|
||||||
@@ -41,7 +40,6 @@ function toggleCarnival() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// observe changes in the DOM
|
|
||||||
const observer = new MutationObserver(toggleCarnival);
|
const observer = new MutationObserver(toggleCarnival);
|
||||||
observer.observe(document.body, {
|
observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
@@ -149,19 +147,8 @@ function createConfettiPiece(container, isInitial = false) {
|
|||||||
container.appendChild(wrapper);
|
container.appendChild(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRandomCarnivalObjects(count) {
|
|
||||||
const carnivalContainer = document.querySelector('.carnival-container');
|
|
||||||
if (!carnivalContainer) return;
|
|
||||||
|
|
||||||
console.log('Adding random carnival confetti');
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
createConfettiPiece(carnivalContainer, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize standard carnival objects
|
// initialize standard carnival objects
|
||||||
function initCarnivalObjects() {
|
function initCarnivalObjects(count) {
|
||||||
let container = document.querySelector('.carnival-container');
|
let container = document.querySelector('.carnival-container');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
@@ -171,7 +158,7 @@ function initCarnivalObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial confetti
|
// Initial confetti
|
||||||
for (let i = 0; i < 60; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
createConfettiPiece(container, true);
|
createConfettiPiece(container, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,13 +166,12 @@ function initCarnivalObjects() {
|
|||||||
// initialize carnival
|
// initialize carnival
|
||||||
function initializeCarnival() {
|
function initializeCarnival() {
|
||||||
if (!carnival) return;
|
if (!carnival) return;
|
||||||
initCarnivalObjects();
|
|
||||||
toggleCarnival();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth;
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomCarnival && (screenWidth > 768 || randomCarnivalMobile)) {
|
const count = !isMobile ? carnivalCount : carnivalCountMobile;
|
||||||
addRandomCarnivalObjects(carnivalCount);
|
|
||||||
}
|
initCarnivalObjects(count);
|
||||||
|
toggleCarnival();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCarnival();
|
initializeCarnival();
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.CherryBlossom || {};
|
const config = window.SeasonalsPluginConfig?.CherryBlossom || {};
|
||||||
|
|
||||||
const cherryBlossom = config.EnableCherryBlossom !== undefined ? config.EnableCherryBlossom : true;
|
const cherryBlossom = config.EnableCherryBlossom !== undefined ? config.EnableCherryBlossom : true; // enable/disable cherryblossom
|
||||||
const petalCount = config.PetalCount || 25;
|
const petalCount = config.PetalCount !== undefined ? config.PetalCount : 25; // count of petal
|
||||||
const randomCherryBlossom = config.EnableRandomCherryBlossom !== undefined ? config.EnableRandomCherryBlossom : true;
|
const petalCountMobile = config.PetalCountMobile !== undefined ? config.PetalCountMobile : 10; // count of petal on mobile
|
||||||
const randomCherryBlossomMobile = config.EnableRandomCherryBlossomMobile !== undefined ? config.EnableRandomCherryBlossomMobile : false;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -67,16 +66,7 @@ function createPetal(container) {
|
|||||||
container.appendChild(petal);
|
container.appendChild(petal);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRandomObjects() {
|
function initObjects(count) {
|
||||||
const container = document.querySelector('.cherryblossom-container');
|
|
||||||
if (!container) return;
|
|
||||||
|
|
||||||
for (let i = 0; i < petalCount; i++) {
|
|
||||||
createPetal(container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initObjects() {
|
|
||||||
let container = document.querySelector('.cherryblossom-container');
|
let container = document.querySelector('.cherryblossom-container');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
@@ -86,20 +76,19 @@ function initObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial batch
|
// Initial batch
|
||||||
for (let i = 0; i < 15; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
createPetal(container);
|
createPetal(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeCherryBlossom() {
|
function initializeCherryBlossom() {
|
||||||
if (!cherryBlossom) return;
|
if (!cherryBlossom) return;
|
||||||
initObjects();
|
|
||||||
toggleCherryBlossom();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth;
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomCherryBlossom && (screenWidth > 768 || randomCherryBlossomMobile)) {
|
const count = !isMobile ? petalCount : petalCountMobile;
|
||||||
addRandomObjects();
|
|
||||||
}
|
initObjects(count);
|
||||||
|
toggleCherryBlossom();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCherryBlossom();
|
initializeCherryBlossom();
|
||||||
|
|||||||
@@ -23,38 +23,13 @@
|
|||||||
text-shadow: 0 0 5px #000;
|
text-shadow: 0 0 5px #000;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
-webkit-user-select: none;
|
|
||||||
-webkit-animation-name: christmas-fall, christmas-shake;
|
|
||||||
-webkit-animation-duration: 10s, 3s;
|
|
||||||
-webkit-animation-timing-function: linear, ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite, infinite;
|
|
||||||
animation-name: christmas-fall, christmas-shake;
|
animation-name: christmas-fall, christmas-shake;
|
||||||
animation-duration: 10s, 3s;
|
animation-duration: 10s, 3s;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
animation-iteration-count: infinite, infinite;
|
animation-iteration-count: infinite, infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes christmas-fall {
|
|
||||||
0% {
|
|
||||||
translate: 0 -10vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
translate: 0 110vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes christmas-shake {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: translateX(80px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes christmas-fall {
|
@keyframes christmas-fall {
|
||||||
0% {
|
0% {
|
||||||
@@ -75,64 +50,4 @@
|
|||||||
50% {
|
50% {
|
||||||
transform: translateX(80px);
|
transform: translateX(80px);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(0) {
|
|
||||||
left: 0%;
|
|
||||||
animation-delay: 0s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(1) {
|
|
||||||
left: 10%;
|
|
||||||
animation-delay: 1s, 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(2) {
|
|
||||||
left: 20%;
|
|
||||||
animation-delay: 6s, 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(3) {
|
|
||||||
left: 30%;
|
|
||||||
animation-delay: 4s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(4) {
|
|
||||||
left: 40%;
|
|
||||||
animation-delay: 2s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(5) {
|
|
||||||
left: 50%;
|
|
||||||
animation-delay: 8s, 3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(6) {
|
|
||||||
left: 60%;
|
|
||||||
animation-delay: 6s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(7) {
|
|
||||||
left: 70%;
|
|
||||||
animation-delay: 2.5s, 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(8) {
|
|
||||||
left: 80%;
|
|
||||||
animation-delay: 1s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(9) {
|
|
||||||
left: 90%;
|
|
||||||
animation-delay: 3s, 1.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(10) {
|
|
||||||
left: 25%;
|
|
||||||
animation-delay: 2s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.christmas:nth-of-type(11) {
|
|
||||||
left: 65%;
|
|
||||||
animation-delay: 4s, 2.5s;
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Christmas || {};
|
const config = window.SeasonalsPluginConfig?.Christmas || {};
|
||||||
|
|
||||||
const christmas = config.EnableChristmas !== undefined ? config.EnableChristmas : true; // enable/disable christmas
|
const christmas = config.EnableChristmas !== undefined ? config.EnableChristmas : true; // enable/disable christmas
|
||||||
const randomChristmas = config.EnableRandomChristmas !== undefined ? config.EnableRandomChristmas : true; // enable random Christmas
|
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const randomChristmasMobile = config.EnableRandomChristmasMobile !== undefined ? config.EnableRandomChristmasMobile : false; // enable random Christmas on mobile devices (Warning: High values may affect performance)
|
const christmasCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol
|
||||||
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different duration for the random Christmas symbols
|
const christmasCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbol on mobile
|
||||||
const christmasCount = config.SymbolCount || 25; // count of random extra christmas
|
|
||||||
|
|
||||||
// Array of christmas characters
|
// Array of christmas characters
|
||||||
const christmasSymbols = ['❆', '🎁', '❄️', '🎁', '🎅', '🎊', '🎁', '🎉'];
|
const christmasSymbols = ['❆', '🎁', '❄️', '🎁', '🎅', '🎊', '🎁', '🎉'];
|
||||||
@@ -45,11 +44,16 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
function addRandomChristmas(count) {
|
function initChristmas(count) {
|
||||||
const christmasContainer = document.querySelector('.christmas-container'); // get the christmas container
|
let christmasContainer = document.querySelector('.christmas-container'); // get the christmas container
|
||||||
if (!christmasContainer) return; // exit if christmas container is not found
|
if (!christmasContainer) {
|
||||||
|
christmasContainer = document.createElement("div");
|
||||||
|
christmasContainer.className = "christmas-container";
|
||||||
|
christmasContainer.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(christmasContainer);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Adding random christmas');
|
console.log('Adding christmas');
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// create a new christmas element
|
// create a new christmas element
|
||||||
@@ -61,8 +65,8 @@ function addRandomChristmas(count) {
|
|||||||
|
|
||||||
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
||||||
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
||||||
const randomAnimationDelay = Math.random() * 12 + 8; // delay (8s to 12s)
|
const randomAnimationDelay = -(Math.random() * 16); // delay (-16s to 0s)
|
||||||
const randomAnimationDelay2 = Math.random() * 5 + 3; // delay (0s to 5s)
|
const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
|
||||||
|
|
||||||
// apply styles
|
// apply styles
|
||||||
christmasDiv.style.left = `${randomLeft}%`;
|
christmasDiv.style.left = `${randomLeft}%`;
|
||||||
@@ -78,46 +82,18 @@ function addRandomChristmas(count) {
|
|||||||
// add the christmas to the container
|
// add the christmas to the container
|
||||||
christmasContainer.appendChild(christmasDiv);
|
christmasContainer.appendChild(christmasDiv);
|
||||||
}
|
}
|
||||||
console.log('Random christmas added');
|
console.log('Christmas added');
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize standard christmas
|
// initialize christmas
|
||||||
function initChristmas() {
|
|
||||||
const christmasContainer = document.querySelector('.christmas-container') || document.createElement("div");
|
|
||||||
|
|
||||||
if (!document.querySelector('.christmas-container')) {
|
|
||||||
christmasContainer.className = "christmas-container";
|
|
||||||
christmasContainer.setAttribute("aria-hidden", "true");
|
|
||||||
document.body.appendChild(christmasContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the 12 standard christmas
|
|
||||||
for (let i = 0; i < 12; i++) {
|
|
||||||
const christmasDiv = document.createElement('div');
|
|
||||||
christmasDiv.className = 'christmas';
|
|
||||||
christmasDiv.textContent = christmasSymbols[Math.floor(Math.random() * christmasSymbols.length)];
|
|
||||||
|
|
||||||
// set random animation duration
|
|
||||||
if (enableDiffrentDuration) {
|
|
||||||
const randomAnimationDuration = Math.random() * 10 + 6; // delay (6s to 10s)
|
|
||||||
const randomAnimationDuration2 = Math.random() * 5 + 2; // delay (2s to 5s)
|
|
||||||
christmasDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
christmasContainer.appendChild(christmasDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize christmas and add random christmas symbols
|
|
||||||
function initializeChristmas() {
|
function initializeChristmas() {
|
||||||
if (!christmas) return; // exit if christmas is disabled
|
if (!christmas) return; // exit if christmas is disabled
|
||||||
initChristmas();
|
|
||||||
toggleChristmas();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomChristmas && (screenWidth > 768 || randomChristmasMobile)) { // add random christmas only on larger screens, unless enabled for mobile devices
|
const count = !isMobile ? christmasCount : christmasCountMobile;
|
||||||
addRandomChristmas(christmasCount);
|
|
||||||
}
|
initChristmas(count);
|
||||||
|
toggleChristmas();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeChristmas();
|
initializeChristmas();
|
||||||
@@ -7,9 +7,11 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.earthday-meadow {
|
.earthday-meadow {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.earthday-sway {
|
.earthday-sway {
|
||||||
|
will-change: transform;
|
||||||
transform-origin: bottom center;
|
transform-origin: bottom center;
|
||||||
animation: sway-grass 4s ease-in-out infinite alternate;
|
animation: sway-grass 4s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.EarthDay || {};
|
const config = window.SeasonalsPluginConfig?.EarthDay || {};
|
||||||
|
|
||||||
const enabled = config.EnableEarthDay !== undefined ? config.EnableEarthDay : true;
|
const enabled = config.EnableEarthDay !== undefined ? config.EnableEarthDay : true; // enable/disable earthday
|
||||||
const vineCount = config.VineCount || 4;
|
const flowersCount = config.FlowersCount !== undefined ? config.FlowersCount : 60; // count of flowers
|
||||||
|
const flowersCountMobile = config.FlowersCountMobile !== undefined ? config.FlowersCountMobile : 20; // count of flowers on mobile
|
||||||
|
|
||||||
const flowerColors = ['#FF69B4', '#FFD700', '#87CEFA', '#FF4500', '#BA55D3', '#FFA500', '#FF1493'];
|
const flowerColors = ['#FF69B4', '#FFD700', '#87CEFA', '#FF4500', '#BA55D3', '#FFA500', '#FF1493'];
|
||||||
|
|
||||||
@@ -68,7 +69,8 @@ function createElements() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate Flowers
|
// Generate Flowers
|
||||||
const flowerCount = Math.max(10, vineCount * 15);
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
const flowerCount = Math.max(5, isMobile ? flowersCountMobile : flowersCount);
|
||||||
for (let i = 0; i < flowerCount; i++) {
|
for (let i = 0; i < flowerCount; i++) {
|
||||||
const x = 10 + Math.random() * (w - 20);
|
const x = 10 + Math.random() * (w - 20);
|
||||||
const y = hSVG * 0.1 + Math.random() * (hSVG * 0.5);
|
const y = hSVG * 0.1 + Math.random() * (hSVG * 0.5);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.easter-grass-container {
|
.easter-grass-container {
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
|
|
||||||
/* sway */
|
/* sway */
|
||||||
.easter-sway {
|
.easter-sway {
|
||||||
|
will-change: transform;
|
||||||
transform-origin: bottom center;
|
transform-origin: bottom center;
|
||||||
animation: easter-wind-sway 6s ease-in-out infinite alternate;
|
animation: easter-wind-sway 6s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Easter || {};
|
const config = window.SeasonalsPluginConfig?.Easter || {};
|
||||||
|
|
||||||
const easter = config.EnableEaster !== undefined ? config.EnableEaster : true;
|
const easter = config.EnableEaster !== undefined ? config.EnableEaster : true; // enable/disable easter
|
||||||
const enableBunny = config.EnableBunny !== undefined ? config.EnableBunny : true;
|
const enableBunny = config.EnableBunny !== undefined ? config.EnableBunny : true; // enable/disable bunny
|
||||||
|
const minBunnyRestTime = config.MinBunnyRestTime !== undefined ? config.MinBunnyRestTime : 2000; // timing parameter
|
||||||
|
const maxBunnyRestTime = config.MaxBunnyRestTime !== undefined ? config.MaxBunnyRestTime : 5000; // timing parameter
|
||||||
|
const eggCount = config.EggCount !== undefined ? config.EggCount : 15; // count of egg
|
||||||
|
|
||||||
/* MARK: Bunny movement config */
|
/* MARK: Bunny movement config */
|
||||||
const jumpDistanceVw = 5; // Distance in vw the bunny covers per jump
|
const jumpDistanceVw = 5; // Distance in vw the bunny covers per jump
|
||||||
const jumpDurationMs = 770; // Time in ms the bunny spends moving during a jump
|
const jumpDurationMs = 770; // Time in ms the bunny spends moving during a jump
|
||||||
const pauseDurationMs = 116.6666; // Time in ms the bunny pauses between jumps
|
const pauseDurationMs = 116.6666; // Time in ms the bunny pauses between jumps
|
||||||
|
|
||||||
const minBunnyRestTime = config.MinBunnyRestTime || 2000;
|
|
||||||
const maxBunnyRestTime = config.MaxBunnyRestTime || 5000;
|
|
||||||
const eggCount = config.EggCount || 15;
|
|
||||||
|
|
||||||
const rabbit = "../Seasonals/Resources/easter_images/Osterhase.gif";
|
const rabbit = "../Seasonals/Resources/easter_images/Osterhase.gif";
|
||||||
|
|
||||||
|
// Credit: https://flaticon.com
|
||||||
const easterEggImages = [
|
const easterEggImages = [
|
||||||
"../Seasonals/Resources/easter_images/egg_1.png",
|
"../Seasonals/Resources/easter_images/egg_1.png",
|
||||||
"../Seasonals/Resources/easter_images/egg_2.png",
|
"../Seasonals/Resources/easter_images/egg_2.png",
|
||||||
@@ -197,6 +198,8 @@ function animateRabbit(rabbit) {
|
|||||||
|
|
||||||
rabbit.style.transition = 'none';
|
rabbit.style.transition = 'none';
|
||||||
const transformScale = startFromLeft ? 'scaleX(-1)' : '';
|
const transformScale = startFromLeft ? 'scaleX(-1)' : '';
|
||||||
|
// Set bounding box center-of-gravity shift when graphic is flipped
|
||||||
|
rabbit.style.transformOrigin = startFromLeft ? '59% 50%' : '50% 50%';
|
||||||
rabbit.style.transform = `translateX(${currentX}vw) ${transformScale}`;
|
rabbit.style.transform = `translateX(${currentX}vw) ${transformScale}`;
|
||||||
|
|
||||||
const loopDurationMs = jumpDurationMs + pauseDurationMs;
|
const loopDurationMs = jumpDurationMs + pauseDurationMs;
|
||||||
@@ -211,10 +214,8 @@ function animateRabbit(rabbit) {
|
|||||||
|
|
||||||
if (!startTime) {
|
if (!startTime) {
|
||||||
startTime = timestamp;
|
startTime = timestamp;
|
||||||
// resetting gif, forces the browser to restart the GIF from the first frame (crucial for syncing hops with movement)
|
|
||||||
const currSrc = rabbit.src.split('?')[0];
|
const currSrc = rabbit.src.split('?')[0];
|
||||||
rabbit.src = '';
|
rabbit.src = currSrc + '?t=' + Date.now();
|
||||||
rabbit.src = currSrc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const elapsed = timestamp - startTime;
|
const elapsed = timestamp - startTime;
|
||||||
@@ -234,7 +235,6 @@ function animateRabbit(rabbit) {
|
|||||||
|
|
||||||
currentX = startX + (completedLoops * jumpDistanceVw + currentLoopDistance) * direction;
|
currentX = startX + (completedLoops * jumpDistanceVw + currentLoopDistance) * direction;
|
||||||
|
|
||||||
// Update DOM without CSS transitions
|
|
||||||
rabbit.style.transform = `translateX(${currentX}vw) ${transformScale}`;
|
rabbit.style.transform = `translateX(${currentX}vw) ${transformScale}`;
|
||||||
|
|
||||||
// Check if finished crossing
|
// Check if finished crossing
|
||||||
@@ -243,6 +243,7 @@ function animateRabbit(rabbit) {
|
|||||||
|
|
||||||
isAnimating = false;
|
isAnimating = false;
|
||||||
rabbitTimeout = setTimeout(() => {
|
rabbitTimeout = setTimeout(() => {
|
||||||
|
if (!document.body.contains(rabbit)) return;
|
||||||
animateRabbit(document.querySelector('#rabbit'));
|
animateRabbit(document.querySelector('#rabbit'));
|
||||||
}, restTime);
|
}, restTime);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eid-symbol {
|
.eid-symbol {
|
||||||
@@ -18,12 +19,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.eid-symbol.floating-star {
|
.eid-symbol.floating-star {
|
||||||
|
will-change: opacity;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
animation: eid-twinkle 4s ease-in-out infinite;
|
animation: eid-twinkle 4s ease-in-out infinite;
|
||||||
mix-blend-mode: screen;
|
mix-blend-mode: screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lantern-rope {
|
.lantern-rope {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Eid || {};
|
const config = window.SeasonalsPluginConfig?.Eid || {};
|
||||||
const eid = config.EnableEid !== undefined ? config.EnableEid : true;
|
const eid = config.EnableEid !== undefined ? config.EnableEid : true; // enable/disable eid
|
||||||
|
const lanternCount = config.LanternCount !== undefined ? config.LanternCount : 8; // count of lantern
|
||||||
|
const lanternCountMobile = config.LanternCountMobile !== undefined ? config.LanternCountMobile : 3; // count of lantern on mobile
|
||||||
|
|
||||||
const eidSymbols = ['🌙', '⭐', '✨'];
|
const eidSymbols = ['🌙', '⭐', '✨'];
|
||||||
|
|
||||||
@@ -39,11 +41,13 @@ observer.observe(document.body, {
|
|||||||
|
|
||||||
function createEid(container) {
|
function createEid(container) {
|
||||||
const starCount = 20;
|
const starCount = 20;
|
||||||
const lanternCount = Math.floor(Math.random() * 3) + 4; // 4 to 6 lanterns
|
|
||||||
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
let activeLanternCount = isMobile ? lanternCountMobile : lanternCount;
|
||||||
|
|
||||||
// Create evenly spaced lanterns
|
// Create evenly spaced lanterns
|
||||||
const segmentWidth = 100 / lanternCount;
|
const segmentWidth = 100 / activeLanternCount;
|
||||||
for (let i = 0; i < lanternCount; i++) {
|
for (let i = 0; i < activeLanternCount; i++) {
|
||||||
const symbol = document.createElement('div');
|
const symbol = document.createElement('div');
|
||||||
symbol.className = 'eid-symbol lantern-rope';
|
symbol.className = 'eid-symbol lantern-rope';
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Eurovision || {};
|
const config = window.SeasonalsPluginConfig?.Eurovision || {};
|
||||||
|
|
||||||
const enabled = config.EnableEurovision !== undefined ? config.EnableEurovision : true;
|
const enabled = config.EnableEurovision !== undefined ? config.EnableEurovision : true; // enable/disable eurovision
|
||||||
const elementCount = config.SymbolCount || 25;
|
const elementCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of notes
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableColorfulNotes = config.EnableColorfulNotes !== undefined ? config.EnableColorfulNotes : true;
|
const enableColorfulNotes = config.EnableColorfulNotes !== undefined ? config.EnableColorfulNotes : true; // enable/disable colorful notes
|
||||||
const eurovisionColorsStr = config.EurovisionColors || '#ff0026ff, #17a6ffff, #32d432ff, #FFD700, #f0821bff, #f826f8ff';
|
const eurovisionColorsStr = config.EurovisionColors !== undefined ? config.EurovisionColors : '#ff0026ff, #17a6ffff, #32d432ff, #FFD700, #f0821bff, #f826f8ff'; // colors to use
|
||||||
const glowSize = config.EurovisionGlowSize !== undefined ? config.EurovisionGlowSize : 2;
|
const glowSize = config.EurovisionGlowSize !== undefined ? config.EurovisionGlowSize : 2; // size of eurovision glow
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
// Toggle Function
|
|
||||||
function toggleEurovision() {
|
function toggleEurovision() {
|
||||||
const container = document.querySelector('.eurovision-container');
|
const container = document.querySelector('.eurovision-container');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|||||||
@@ -22,8 +22,9 @@
|
|||||||
|
|
||||||
/* Film grain */
|
/* Film grain */
|
||||||
.filmnoir-grain {
|
.filmnoir-grain {
|
||||||
|
will-change: transform, opacity;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -50%;
|
top: 0;
|
||||||
left: -50%;
|
left: -50%;
|
||||||
width: 200%;
|
width: 200%;
|
||||||
height: 200%;
|
height: 200%;
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
mix-blend-mode: overlay;
|
mix-blend-mode: overlay;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
translate: 0 -50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vignette */
|
/* Vignette */
|
||||||
@@ -48,6 +50,7 @@
|
|||||||
|
|
||||||
/* Occasional flicker and scratch */
|
/* Occasional flicker and scratch */
|
||||||
.filmnoir-scratches {
|
.filmnoir-scratches {
|
||||||
|
will-change: opacity;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.FilmNoir || {};
|
const config = window.SeasonalsPluginConfig?.FilmNoir || {};
|
||||||
const filmnoir = config.EnableFilmNoir !== undefined ? config.EnableFilmNoir : true;
|
const filmnoir = config.EnableFilmNoir !== undefined ? config.EnableFilmNoir : true; // enable/disable filmnoir
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rocket-trail {
|
.rocket-trail {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: var(--trailX);
|
left: var(--trailX);
|
||||||
top: var(--trailStartY);
|
top: 0;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
|
|
||||||
/* activate the following for rocket trail */
|
/* activate the following for rocket trail */
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
box-shadow: 0 0 8px 2px white;*/
|
box-shadow: 0 0 8px 2px white;*/
|
||||||
|
|
||||||
animation: rocket-trail-animation 1s linear forwards;
|
animation: rocket-trail-animation 1s linear forwards;
|
||||||
|
translate: 0 var(--trailStartY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes rocket-trail-animation {
|
@keyframes rocket-trail-animation {
|
||||||
@@ -56,6 +58,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.firework {
|
.firework {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ const config = window.SeasonalsPluginConfig?.Fireworks || {};
|
|||||||
|
|
||||||
const fireworks = config.EnableFireworks !== undefined ? config.EnableFireworks : true; // enable/disable fireworks
|
const fireworks = config.EnableFireworks !== undefined ? config.EnableFireworks : true; // enable/disable fireworks
|
||||||
const scrollFireworks = config.ScrollFireworks !== undefined ? config.ScrollFireworks : true; // enable fireworks to scroll with page content
|
const scrollFireworks = config.ScrollFireworks !== undefined ? config.ScrollFireworks : true; // enable fireworks to scroll with page content
|
||||||
const particlesPerFirework = config.ParticleCount || 50; // count of particles per firework (Warning: High values may affect performance)
|
const particlesPerFirework = config.ParticleCount !== undefined ? config.ParticleCount : 50; // count of particles per firework
|
||||||
const minFireworks = config.MinFireworks || 3; // minimum number of simultaneous fireworks
|
const minFireworks = config.MinFireworks !== undefined ? config.MinFireworks : 3; // minimum number of simultaneous fireworks
|
||||||
const maxFireworks = config.MaxFireworks || 6; // maximum number of simultaneous fireworks
|
const maxFireworks = config.MaxFireworks !== undefined ? config.MaxFireworks : 6; // maximum number of simultaneous fireworks
|
||||||
const intervalOfFireworks = config.LaunchInterval || 3200; // interval for the fireworks in milliseconds
|
const intervalOfFireworks = config.LaunchInterval !== undefined ? config.LaunchInterval : 3200; // interval for the fireworks in milliseconds
|
||||||
|
|
||||||
// array of color palettes for the fireworks
|
// array of color palettes for the fireworks
|
||||||
const colorPalettes = [
|
const colorPalettes = [
|
||||||
@@ -162,6 +162,7 @@ function startFireworks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fireworksInterval = setInterval(() => {
|
fireworksInterval = setInterval(() => {
|
||||||
|
if (!document.body.contains(fireworkContainer)) { clearInterval(fireworksInterval); return; }
|
||||||
const randomCount = Math.floor(Math.random() * maxFireworks) + minFireworks;
|
const randomCount = Math.floor(Math.random() * maxFireworks) + minFireworks;
|
||||||
for (let i = 0; i < randomCount; i++) {
|
for (let i = 0; i < randomCount; i++) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Friday13 || {};
|
const config = window.SeasonalsPluginConfig?.Friday13 || {};
|
||||||
const friday13 = config.EnableFriday13 !== undefined ? config.EnableFriday13 : true;
|
const friday13 = config.EnableFriday13 !== undefined ? config.EnableFriday13 : true; // enable/disable friday13
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -61,12 +61,12 @@ function createFriday13(container) {
|
|||||||
cat.parentNode.removeChild(cat);
|
cat.parentNode.removeChild(cat);
|
||||||
}
|
}
|
||||||
// Respawn with random delay between 5 to 25 seconds
|
// Respawn with random delay between 5 to 25 seconds
|
||||||
setTimeout(spawnCat, Math.random() * 20000 + 5000);
|
setTimeout(() => { if (document.body.contains(container)) spawnCat(); }, Math.random() * 20000 + 5000);
|
||||||
}, (catWalkDurationSeconds * 1000) + 500); // Wait for duration + 500ms safety margin
|
}, (catWalkDurationSeconds * 1000) + 500); // Wait for duration + 500ms safety margin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial spawn with random delay
|
// Initial spawn with random delay
|
||||||
setTimeout(spawnCat, Math.random() * 5000);
|
setTimeout(() => { if (document.body.contains(container)) spawnCat(); }, Math.random() * 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeFriday13() {
|
function initializeFriday13() {
|
||||||
|
|||||||
@@ -9,16 +9,17 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.frost-layer {
|
.frost-layer {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
/* A glowing white-blue gradient from edges */
|
|
||||||
background: radial-gradient(ellipse at center, transparent 60%, rgba(180, 220, 255, 0.4) 100%);
|
background: radial-gradient(ellipse at center, transparent 60%, rgba(180, 220, 255, 0.4) 100%);
|
||||||
box-shadow: inset 0 0 60px rgba(200, 230, 255, 0.5), inset 0 0 120px rgba(255, 255, 255, 0.3);
|
box-shadow: inset 0 0 60px rgba(200, 230, 255, 0.5), inset 0 0 120px rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
@@ -27,14 +28,13 @@
|
|||||||
animation: frost-creep 4s ease-out forwards;
|
animation: frost-creep 4s ease-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subtle repeating star/crystal pattern */
|
|
||||||
.frost-crystals {
|
.frost-crystals {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -5%;
|
top: 0;
|
||||||
left: -5%;
|
left: -5%;
|
||||||
width: 110%;
|
width: 110%;
|
||||||
height: 110%;
|
height: 110%;
|
||||||
/* Use multi-layered star patterns for a random, crystalline spread */
|
|
||||||
background-image:
|
background-image:
|
||||||
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"><circle cx="10" cy="10" r="1.5" fill="rgba(255,255,255,0.2)"/><circle cx="40" cy="30" r="1" fill="rgba(255,255,255,0.15)"/><circle cx="20" cy="50" r="2" fill="rgba(255,255,255,0.1)"/><path d="M50 10 L51 15 L56 16 L51 17 L50 22 L49 17 L44 16 L49 15 Z" fill="rgba(255,255,255,0.2)"/></svg>'),
|
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"><circle cx="10" cy="10" r="1.5" fill="rgba(255,255,255,0.2)"/><circle cx="40" cy="30" r="1" fill="rgba(255,255,255,0.15)"/><circle cx="20" cy="50" r="2" fill="rgba(255,255,255,0.1)"/><path d="M50 10 L51 15 L56 16 L51 17 L50 22 L49 17 L44 16 L49 15 Z" fill="rgba(255,255,255,0.2)"/></svg>'),
|
||||||
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40"><circle cx="5" cy="20" r="1" fill="rgba(255,255,255,0.15)"/><circle cx="25" cy="5" r="1.5" fill="rgba(255,255,255,0.1)"/><path d="M20 20 L21 23 L24 24 L21 25 L20 28 L19 25 L16 24 L19 23 Z" fill="rgba(255,255,255,0.15)"/></svg>'),
|
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40"><circle cx="5" cy="20" r="1" fill="rgba(255,255,255,0.15)"/><circle cx="25" cy="5" r="1.5" fill="rgba(255,255,255,0.1)"/><path d="M20 20 L21 23 L24 24 L21 25 L20 28 L19 25 L16 24 L19 23 Z" fill="rgba(255,255,255,0.15)"/></svg>'),
|
||||||
@@ -43,12 +43,9 @@
|
|||||||
background-size: 110px 110px, 60px 60px, 30px 30px;
|
background-size: 110px 110px, 60px 60px, 30px 30px;
|
||||||
background-position: 0 0, 15px 15px, 5px 10px;
|
background-position: 0 0, 15px 15px, 5px 10px;
|
||||||
mix-blend-mode: overlay;
|
mix-blend-mode: overlay;
|
||||||
|
|
||||||
/* Mask out the center so crystals only appear strongly on the edges */
|
|
||||||
-webkit-mask-image: radial-gradient(ellipse at center, transparent 50%, black 100%);
|
|
||||||
mask-image: radial-gradient(ellipse at center, transparent 50%, black 100%);
|
mask-image: radial-gradient(ellipse at center, transparent 50%, black 100%);
|
||||||
|
|
||||||
animation: frost-shimmer 6s infinite alternate ease-in-out;
|
animation: frost-shimmer 6s infinite alternate ease-in-out;
|
||||||
|
translate: 0 -5vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes frost-creep {
|
@keyframes frost-creep {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Frost || {};
|
const config = window.SeasonalsPluginConfig?.Frost || {};
|
||||||
|
|
||||||
const frost = config.EnableFrost !== undefined ? config.EnableFrost : true;
|
const frost = config.EnableFrost !== undefined ? config.EnableFrost : true; // enable/disable frost
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -7,25 +7,17 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 10000;
|
z-index: 10;
|
||||||
contain: layout paint;
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.halloween {
|
.halloween {
|
||||||
|
will-change: transform;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: -10%;
|
bottom: -10%;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
-webkit-animation-name: halloween-fall, halloween-shake;
|
|
||||||
-webkit-animation-duration: 10s, 3s;
|
|
||||||
-webkit-animation-timing-function: linear, ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite, infinite;
|
|
||||||
-webkit-animation-play-state: running, running;
|
|
||||||
animation-name: halloween-fall, halloween-shake;
|
animation-name: halloween-fall, halloween-shake;
|
||||||
animation-duration: 10s, 3s;
|
animation-duration: 10s, 3s;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
@@ -33,29 +25,7 @@
|
|||||||
animation-play-state: running, running
|
animation-play-state: running, running
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes halloween-fall {
|
|
||||||
0% {
|
|
||||||
bottom: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
bottom: 110%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes halloween-shake {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
-webkit-transform: translateX(80px);
|
|
||||||
transform: translateX(80px)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes halloween-fall {
|
@keyframes halloween-fall {
|
||||||
0% {
|
0% {
|
||||||
@@ -79,78 +49,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.halloween:nth-of-type(0) {
|
|
||||||
left: 1%;
|
|
||||||
-webkit-animation-delay: 0s, 0s;
|
|
||||||
animation-delay: 0s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(1) {
|
|
||||||
left: 10%;
|
|
||||||
-webkit-animation-delay: -1s, -1s;
|
|
||||||
animation-delay: -1s, -1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(2) {
|
|
||||||
left: 20%;
|
|
||||||
-webkit-animation-delay: -2s, -2s;
|
|
||||||
animation-delay: -2s, -2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(3) {
|
|
||||||
left: 30%;
|
|
||||||
-webkit-animation-delay: -3s, -3s;
|
|
||||||
animation-delay: -3s, -3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(4) {
|
|
||||||
left: 40%;
|
|
||||||
-webkit-animation-delay: -4s, -4s;
|
|
||||||
animation-delay: -4s, -4s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(5) {
|
|
||||||
left: 50%;
|
|
||||||
-webkit-animation-delay: -5s, -5s;
|
|
||||||
animation-delay: -5s, -5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(6) {
|
|
||||||
left: 60%;
|
|
||||||
-webkit-animation-delay: -6s, -6s;
|
|
||||||
animation-delay: -6s, -6s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(7) {
|
|
||||||
left: 70%;
|
|
||||||
-webkit-animation-delay: -7s, -7s;
|
|
||||||
animation-delay: -7s, -7s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(8) {
|
|
||||||
left: 80%;
|
|
||||||
-webkit-animation-delay: -8s, -8s;
|
|
||||||
animation-delay: -8s, -8s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(9) {
|
|
||||||
left: 90%;
|
|
||||||
-webkit-animation-delay: -9s, -9s;
|
|
||||||
animation-delay: -9s, -9s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(10) {
|
|
||||||
left: 25%;
|
|
||||||
-webkit-animation-delay: -10s, -10s;
|
|
||||||
animation-delay: -10s, -10s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.halloween:nth-of-type(11) {
|
|
||||||
left: 65%;
|
|
||||||
-webkit-animation-delay: -11s, -11s;
|
|
||||||
animation-delay: -11s, -11s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- Fog Layer --- */
|
/* --- Fog Layer --- */
|
||||||
.halloween-fog-layer {
|
.halloween-fog-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -162,7 +60,6 @@
|
|||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
mask-image: linear-gradient(to top, black, transparent);
|
mask-image: linear-gradient(to top, black, transparent);
|
||||||
-webkit-mask-image: linear-gradient(to top, black, transparent);
|
|
||||||
}
|
}
|
||||||
.halloween-fog-blob {
|
.halloween-fog-blob {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -174,10 +71,12 @@
|
|||||||
filter: blur(15px);
|
filter: blur(15px);
|
||||||
}
|
}
|
||||||
.halloween-fog-blob:nth-child(1) {
|
.halloween-fog-blob:nth-child(1) {
|
||||||
|
will-change: transform;
|
||||||
left: -20vw;
|
left: -20vw;
|
||||||
animation: fog-float1 25s ease-in-out infinite alternate;
|
animation: fog-float1 25s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
.halloween-fog-blob:nth-child(2) {
|
.halloween-fog-blob:nth-child(2) {
|
||||||
|
will-change: transform;
|
||||||
left: -50vw;
|
left: -50vw;
|
||||||
background: radial-gradient(ellipse at center, rgba(100, 110, 120, 0.3) 0%, transparent 65%);
|
background: radial-gradient(ellipse at center, rgba(100, 110, 120, 0.3) 0%, transparent 65%);
|
||||||
animation: fog-float2 35s ease-in-out infinite alternate;
|
animation: fog-float2 35s ease-in-out infinite alternate;
|
||||||
@@ -196,7 +95,7 @@
|
|||||||
/* --- Spiders --- */
|
/* --- Spiders --- */
|
||||||
.halloween-spider-wrapper {
|
.halloween-spider-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -50px;
|
top: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -204,8 +103,10 @@
|
|||||||
transform-origin: top;
|
transform-origin: top;
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
padding: 20px; /* Increase hit area safely */
|
padding: 20px; /* Increase hit area */
|
||||||
|
translate: 0 -50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.halloween-thread {
|
.halloween-thread {
|
||||||
width: 30px; /* Wider hit area for mouse interaction */
|
width: 30px; /* Wider hit area for mouse interaction */
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@@ -223,12 +124,12 @@
|
|||||||
background: linear-gradient(to bottom, rgba(200, 200, 200, 0.1), rgba(200, 200, 200, 0.6));
|
background: linear-gradient(to bottom, rgba(200, 200, 200, 0.1), rgba(200, 200, 200, 0.6));
|
||||||
}
|
}
|
||||||
.halloween-spider {
|
.halloween-spider {
|
||||||
|
will-change: transform;
|
||||||
animation: spider-swing 3s ease-in-out infinite alternate;
|
animation: spider-swing 3s ease-in-out infinite alternate;
|
||||||
transform-origin: top center;
|
transform-origin: top center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MARK: SPIDER SWAY CONFIGURATION */
|
/* MARK: SPIDER SWAY CONFIGURATION */
|
||||||
/* Adjust degrees in 'rotate(...)' to change how far spider and thread swing in wind. */
|
|
||||||
@keyframes wind-sway {
|
@keyframes wind-sway {
|
||||||
0% { transform: rotate(0deg); }
|
0% { transform: rotate(0deg); }
|
||||||
25% { transform: rotate(2deg); }
|
25% { transform: rotate(2deg); }
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Halloween || {};
|
const config = window.SeasonalsPluginConfig?.Halloween || {};
|
||||||
|
|
||||||
const halloween = config.EnableHalloween !== undefined ? config.EnableHalloween : true; // enable/disable halloween
|
const halloween = config.EnableHalloween !== undefined ? config.EnableHalloween : true; // enable/disable halloween
|
||||||
const randomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; // enable more random symbols
|
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const randomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; // enable random symbols on mobile devices (Warning: High values may affect performance)
|
const enableSpiders = config.EnableSpiders !== undefined ? config.EnableSpiders : true; // enable/disable spiders
|
||||||
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different duration for the random halloween symbols
|
const enableMice = config.EnableMice !== undefined ? config.EnableMice : true; // enable/disable mice
|
||||||
const enableSpiders = config.EnableSpiders !== undefined ? config.EnableSpiders : true;
|
const halloweenCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbols
|
||||||
const enableMice = config.EnableMice !== undefined ? config.EnableMice : true;
|
const halloweenCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbols on mobile
|
||||||
const halloweenCount = config.SymbolCount || 25; // count of random extra symbols
|
|
||||||
|
|
||||||
const images = [
|
const images = [
|
||||||
"../Seasonals/Resources/halloween_images/ghost_20x20.png",
|
"../Seasonals/Resources/halloween_images/ghost_20x20.png",
|
||||||
@@ -14,7 +13,7 @@ const images = [
|
|||||||
"../Seasonals/Resources/halloween_images/pumpkin_20x20.png",
|
"../Seasonals/Resources/halloween_images/pumpkin_20x20.png",
|
||||||
];
|
];
|
||||||
|
|
||||||
let msgPrinted = false; // flag to prevent multiple console messages
|
let msgPrinted = false;
|
||||||
|
|
||||||
// function to check and control the halloween
|
// function to check and control the halloween
|
||||||
function toggleHalloween() {
|
function toggleHalloween() {
|
||||||
@@ -42,7 +41,6 @@ function toggleHalloween() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// observe changes in the DOM
|
|
||||||
const observer = new MutationObserver(toggleHalloween);
|
const observer = new MutationObserver(toggleHalloween);
|
||||||
observer.observe(document.body, {
|
observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
@@ -51,29 +49,31 @@ observer.observe(document.body, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function addRandomSymbols(count) {
|
function initHalloween(count) {
|
||||||
const halloweenContainer = document.querySelector('.halloween-container'); // get the halloween container
|
let halloweenContainer = document.querySelector('.halloween-container');
|
||||||
if (!halloweenContainer) return; // exit if halloween container is not found
|
if (!halloweenContainer) {
|
||||||
|
halloweenContainer = document.createElement("div");
|
||||||
console.log('Adding random halloween symbols');
|
halloweenContainer.className = "halloween-container";
|
||||||
|
halloweenContainer.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(halloweenContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Adding halloween symbols');
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// create a new halloween elements
|
|
||||||
const halloweenDiv = document.createElement("div");
|
const halloweenDiv = document.createElement("div");
|
||||||
halloweenDiv.className = "halloween";
|
halloweenDiv.className = "halloween";
|
||||||
|
|
||||||
// pick a random halloween symbol
|
|
||||||
const imageSrc = images[Math.floor(Math.random() * images.length)];
|
const imageSrc = images[Math.floor(Math.random() * images.length)];
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = imageSrc;
|
img.src = imageSrc;
|
||||||
|
|
||||||
halloweenDiv.appendChild(img);
|
halloweenDiv.appendChild(img);
|
||||||
|
|
||||||
|
|
||||||
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
|
||||||
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
||||||
const randomAnimationDelay = Math.random() * 10; // delay (0s to 10s)
|
const randomAnimationDelay = Math.random() * 10; // delay (0s to 10s)
|
||||||
|
// Display directly symbols on full screen (below) or let it build up (above)
|
||||||
|
// const randomAnimationDelay = -(Math.random() * 10); // delay (-10s to 0s)
|
||||||
const randomAnimationDelay2 = -(Math.random() * 3); // delay (-3s to 0s)
|
const randomAnimationDelay2 = -(Math.random() * 3); // delay (-3s to 0s)
|
||||||
|
|
||||||
// apply styles
|
// apply styles
|
||||||
@@ -87,41 +87,9 @@ function addRandomSymbols(count) {
|
|||||||
halloweenDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
halloweenDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the halloween to the container
|
|
||||||
halloweenContainer.appendChild(halloweenDiv);
|
halloweenContainer.appendChild(halloweenDiv);
|
||||||
}
|
}
|
||||||
console.log('Random halloween symbols added');
|
console.log('Halloween symbols added');
|
||||||
}
|
|
||||||
|
|
||||||
// create halloween objects
|
|
||||||
function createHalloween() {
|
|
||||||
const container = document.querySelector('.halloween-container') || document.createElement("div");
|
|
||||||
|
|
||||||
if (!document.querySelector('.halloween-container')) {
|
|
||||||
container.className = "halloween-container";
|
|
||||||
container.setAttribute("aria-hidden", "true");
|
|
||||||
document.body.appendChild(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
|
||||||
images.forEach(imageSrc => {
|
|
||||||
const halloweenDiv = document.createElement("div");
|
|
||||||
halloweenDiv.className = "halloween";
|
|
||||||
|
|
||||||
const img = document.createElement("img");
|
|
||||||
img.src = imageSrc;
|
|
||||||
|
|
||||||
// set random animation duration
|
|
||||||
if (enableDiffrentDuration) {
|
|
||||||
const randomAnimationDuration = Math.random() * 10 + 6; // delay (6s to 10s)
|
|
||||||
const randomAnimationDuration2 = Math.random() * 5 + 2; // delay (2s to 5s)
|
|
||||||
halloweenDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
halloweenDiv.appendChild(img);
|
|
||||||
container.appendChild(halloweenDiv);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create fog layer
|
// create fog layer
|
||||||
@@ -182,14 +150,18 @@ function createSpider(container) {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
setTimeout(() => createSpider(container), Math.random() * 5000 + 1000);
|
if (document.body.contains(container)) {
|
||||||
|
setTimeout(() => createSpider(container), Math.random() * 5000 + 1000);
|
||||||
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.addEventListener('animationend', () => {
|
wrapper.addEventListener('animationend', () => {
|
||||||
if (isRetreating) return;
|
if (isRetreating) return;
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
setTimeout(() => createSpider(container), Math.random() * 5000 + 1000);
|
if (document.body.contains(container)) {
|
||||||
|
setTimeout(() => createSpider(container), Math.random() * 5000 + 1000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
container.appendChild(wrapper);
|
container.appendChild(wrapper);
|
||||||
@@ -223,16 +195,21 @@ function createMouse(container) {
|
|||||||
|
|
||||||
mouse.addEventListener('animationend', () => {
|
mouse.addEventListener('animationend', () => {
|
||||||
mouse.remove();
|
mouse.remove();
|
||||||
setTimeout(() => createMouse(container), Math.random() * 4000 + 2000);
|
if (document.body.contains(container)) {
|
||||||
|
setTimeout(() => createMouse(container), Math.random() * 4000 + 2000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
container.appendChild(mouse);
|
container.appendChild(mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize halloween
|
|
||||||
function initializeHalloween() {
|
function initializeHalloween() {
|
||||||
if (!halloween) return; // exit if halloween is disabled
|
if (!halloween) return;
|
||||||
createHalloween();
|
|
||||||
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
const count = !isMobile ? halloweenCount : halloweenCountMobile;
|
||||||
|
|
||||||
|
initHalloween(count);
|
||||||
toggleHalloween();
|
toggleHalloween();
|
||||||
|
|
||||||
const container = document.querySelector('.halloween-container');
|
const container = document.querySelector('.halloween-container');
|
||||||
@@ -254,11 +231,6 @@ function initializeHalloween() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
|
||||||
if (randomSymbols && (screenWidth > 768 || randomSymbolsMobile)) { // add random halloweens only on larger screens, unless enabled for mobile devices
|
|
||||||
addRandomSymbols(halloweenCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeHalloween();
|
initializeHalloween();
|
||||||
@@ -12,48 +12,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.heart {
|
.heart {
|
||||||
|
will-change: transform;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: -10%;
|
bottom: -10%;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
-webkit-animation-name: heart-fall, heart-shake;
|
|
||||||
-webkit-animation-duration: 14s, 5s;
|
|
||||||
-webkit-animation-timing-function: linear, ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite, infinite;
|
|
||||||
animation-name: heart-fall, heart-shake;
|
animation-name: heart-fall, heart-shake;
|
||||||
animation-duration: 14s, 5s;
|
animation-duration: 14s, 5s;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
animation-iteration-count: infinite, infinite;
|
animation-iteration-count: infinite, infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes heart-fall {
|
|
||||||
0% {
|
|
||||||
bottom: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
bottom: 110%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes heart-shake {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
-webkit-transform: translateX(80px);
|
|
||||||
transform: translateX(80px)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes heart-fall {
|
@keyframes heart-fall {
|
||||||
0% {
|
0% {
|
||||||
@@ -76,75 +49,3 @@
|
|||||||
transform: translateX(80px)
|
transform: translateX(80px)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.heart:nth-of-type(0) {
|
|
||||||
left: 1%;
|
|
||||||
-webkit-animation-delay: 0s, 0s;
|
|
||||||
animation-delay: 0s, 0s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(1) {
|
|
||||||
left: 10%;
|
|
||||||
-webkit-animation-delay: 1s, 1s;
|
|
||||||
animation-delay: 1s, 1s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(2) {
|
|
||||||
left: 20%;
|
|
||||||
-webkit-animation-delay: 6s, .5s;
|
|
||||||
animation-delay: 6s, .5s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(3) {
|
|
||||||
left: 30%;
|
|
||||||
-webkit-animation-delay: 4s, 2s;
|
|
||||||
animation-delay: 4s, 2s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(4) {
|
|
||||||
left: 40%;
|
|
||||||
-webkit-animation-delay: 2s, 2s;
|
|
||||||
animation-delay: 2s, 2s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(5) {
|
|
||||||
left: 50%;
|
|
||||||
-webkit-animation-delay: 8s, 3s;
|
|
||||||
animation-delay: 8s, 3s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(6) {
|
|
||||||
left: 60%;
|
|
||||||
-webkit-animation-delay: 6s, 2s;
|
|
||||||
animation-delay: 6s, 2s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(7) {
|
|
||||||
left: 70%;
|
|
||||||
-webkit-animation-delay: 2.5s, 1s;
|
|
||||||
animation-delay: 2.5s, 1s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(8) {
|
|
||||||
left: 80%;
|
|
||||||
-webkit-animation-delay: 1s, 0s;
|
|
||||||
animation-delay: 1s, 0s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(9) {
|
|
||||||
left: 90%;
|
|
||||||
-webkit-animation-delay: 3s, 1.5s;
|
|
||||||
animation-delay: 3s, 1.5s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(10) {
|
|
||||||
left: 25%;
|
|
||||||
-webkit-animation-delay: 2s, 0s;
|
|
||||||
animation-delay: 2s, 0s
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart:nth-of-type(11) {
|
|
||||||
left: 65%;
|
|
||||||
-webkit-animation-delay: 4s, 2.5s;
|
|
||||||
animation-delay: 4s, 2.5s
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Hearts || {};
|
const config = window.SeasonalsPluginConfig?.Hearts || {};
|
||||||
|
|
||||||
const hearts = config.EnableHearts !== undefined ? config.EnableHearts : true; // enable/disable hearts
|
const hearts = config.EnableHearts !== undefined ? config.EnableHearts : true; // enable/disable hearts
|
||||||
const randomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true; // enable more random symbols
|
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const randomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false; // enable random symbols on mobile devices (Warning: High values may affect performance)
|
const heartsCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbol
|
||||||
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different animation duration for random symbols
|
const heartsCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbol on mobile
|
||||||
const heartsCount = config.SymbolCount || 25; // count of random extra symbols
|
|
||||||
|
|
||||||
// Array of hearts characters
|
// Array of hearts characters
|
||||||
const heartSymbols = ['❤️', '💕', '💞', '💓', '💗', '💖'];
|
const heartSymbols = ['❤️', '💕', '💞', '💓', '💗', '💖'];
|
||||||
@@ -46,11 +45,16 @@ observer.observe(document.body, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function addRandomSymbols(count) {
|
function initHearts(count) {
|
||||||
const heartsContainer = document.querySelector('.hearts-container'); // get the hearts container
|
let heartsContainer = document.querySelector('.hearts-container'); // get the hearts container
|
||||||
if (!heartsContainer) return; // exit if hearts container is not found
|
if (!heartsContainer) {
|
||||||
|
heartsContainer = document.createElement("div");
|
||||||
|
heartsContainer.className = "hearts-container";
|
||||||
|
heartsContainer.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(heartsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Adding random heart symbols');
|
console.log('Adding heart symbols');
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// create a new hearts elements
|
// create a new hearts elements
|
||||||
@@ -63,8 +67,8 @@ function addRandomSymbols(count) {
|
|||||||
|
|
||||||
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
||||||
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
||||||
const randomAnimationDelay = Math.random() * 14; // delay (0s to 14s)
|
const randomAnimationDelay = -(Math.random() * 16); // delay (-16s to 0s)
|
||||||
const randomAnimationDelay2 = Math.random() * 5; // delay (0s to 5s)
|
const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
|
||||||
|
|
||||||
// apply styles
|
// apply styles
|
||||||
heartsDiv.style.left = `${randomLeft}%`;
|
heartsDiv.style.left = `${randomLeft}%`;
|
||||||
@@ -80,46 +84,18 @@ function addRandomSymbols(count) {
|
|||||||
// add the hearts to the container
|
// add the hearts to the container
|
||||||
heartsContainer.appendChild(heartsDiv);
|
heartsContainer.appendChild(heartsDiv);
|
||||||
}
|
}
|
||||||
console.log('Random hearts symbols added');
|
console.log('Heart symbols added');
|
||||||
}
|
}
|
||||||
|
|
||||||
// create hearts objects
|
|
||||||
function createHearts() {
|
|
||||||
const container = document.querySelector('.hearts-container') || document.createElement("div");
|
|
||||||
|
|
||||||
if (!document.querySelector('.hearts-container')) {
|
|
||||||
container.className = "hearts-container";
|
|
||||||
container.setAttribute("aria-hidden", "true");
|
|
||||||
document.body.appendChild(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < 12; i++) {
|
|
||||||
const heartsDiv = document.createElement("div");
|
|
||||||
heartsDiv.className = "heart";
|
|
||||||
heartsDiv.textContent = heartSymbols[i % heartSymbols.length];
|
|
||||||
|
|
||||||
// set random animation duration
|
|
||||||
if (enableDiffrentDuration) {
|
|
||||||
const randomAnimationDuration = Math.random() * 16 + 12; // delay (12s to 16s)
|
|
||||||
const randomAnimationDuration2 = Math.random() * 7 + 3; // delay (3s to 7s)
|
|
||||||
heartsDiv.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
container.appendChild(heartsDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// initialize hearts
|
// initialize hearts
|
||||||
function initializeHearts() {
|
function initializeHearts() {
|
||||||
if (!hearts) return; // exit if hearts is disabled
|
if (!hearts) return; // exit if hearts is disabled
|
||||||
createHearts();
|
|
||||||
toggleHearts();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomSymbols && (screenWidth > 768 || randomSymbolsMobile)) { // add random heartss only on larger screens, unless enabled for mobile devices
|
const count = !isMobile ? heartsCount : heartsCountMobile;
|
||||||
addRandomSymbols(heartsCount);
|
|
||||||
}
|
initHearts(count);
|
||||||
|
toggleHearts();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeHearts();
|
initializeHearts();
|
||||||
@@ -29,11 +29,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mario-jump {
|
.mario-jump {
|
||||||
|
will-change: transform;
|
||||||
animation: jump-arc 0.8s ease-in-out;
|
animation: jump-arc 0.8s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 8-bit coin styling */
|
/* 8-bit coin styling */
|
||||||
.mario-coin {
|
.mario-coin {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@@ -47,11 +49,12 @@
|
|||||||
.mario-coin::after {
|
.mario-coin::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 0;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
background: #daa520;
|
background: #daa520;
|
||||||
|
translate: 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes mario-run {
|
@keyframes mario-run {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.MarioDay || {};
|
const config = window.SeasonalsPluginConfig?.MarioDay || {};
|
||||||
const marioday = config.EnableMarioDay !== undefined ? config.EnableMarioDay : true;
|
const marioday = config.EnableMarioDay !== undefined ? config.EnableMarioDay : true; // enable/disable marioday
|
||||||
|
const letMarioJump = config.LetMarioJump !== undefined ? config.LetMarioJump : true; // optionally let mario jump occasionally
|
||||||
|
|
||||||
|
// Credit: https://gifs.alphacoders.com/gifs/view/2585
|
||||||
|
const marioImage = '../Seasonals/Resources/mario_assets/mario.gif';
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -36,26 +40,49 @@ observer.observe(document.body, {
|
|||||||
|
|
||||||
|
|
||||||
function createMarioDay(container) {
|
function createMarioDay(container) {
|
||||||
|
// MARK: Mario's running speed across the screen
|
||||||
|
const marioSpeedSeconds = 18;
|
||||||
|
|
||||||
const wrapper = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
wrapper.className = 'mario-wrapper';
|
wrapper.className = 'mario-wrapper';
|
||||||
|
wrapper.style.animationDuration = `${marioSpeedSeconds}s`;
|
||||||
|
|
||||||
const mario = document.createElement('img');
|
const mario = document.createElement('img');
|
||||||
mario.className = 'mario-runner';
|
mario.className = 'mario-runner';
|
||||||
mario.src = '../Seasonals/Resources/mario_assets/mario.gif';
|
mario.src = marioImage;
|
||||||
|
|
||||||
wrapper.appendChild(mario);
|
wrapper.appendChild(mario);
|
||||||
container.appendChild(wrapper);
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
let jumpCount = 0;
|
||||||
|
let maxJumpsForThisRun = Math.floor(Math.random() * 3); // 0, 1, or 2
|
||||||
|
|
||||||
|
const resetJumpInterval = setInterval(() => {
|
||||||
|
if (!document.body.contains(container)) { clearInterval(resetJumpInterval); return; }
|
||||||
|
jumpCount = 0;
|
||||||
|
maxJumpsForThisRun = Math.floor(Math.random() * 3); // Randomize jumps for the next pass
|
||||||
|
}, (marioSpeedSeconds / 2) * 1000);
|
||||||
|
|
||||||
// Periodically throw out an 8-bit coin
|
// Periodically throw out an 8-bit coin
|
||||||
setInterval(() => {
|
const intervalId = setInterval(() => {
|
||||||
if (!document.querySelector('.marioday-container')) return;
|
if (!document.body.contains(container)) { clearInterval(intervalId); return; }
|
||||||
|
if (container.style.display === 'none') return;
|
||||||
|
|
||||||
|
const marioRect = wrapper.getBoundingClientRect();
|
||||||
|
if (marioRect.left < 0 || marioRect.right > window.innerWidth) return;
|
||||||
|
|
||||||
|
if (letMarioJump && !mario.classList.contains('mario-jump') && jumpCount < maxJumpsForThisRun) {
|
||||||
|
mario.classList.add('mario-jump');
|
||||||
|
jumpCount++;
|
||||||
|
setTimeout(() => mario.classList.remove('mario-jump'), 800);
|
||||||
|
}
|
||||||
|
|
||||||
const coin = document.createElement('div');
|
const coin = document.createElement('div');
|
||||||
coin.className = 'mario-coin';
|
coin.className = 'mario-coin';
|
||||||
|
|
||||||
// Grab Mario's current screen position to lock the coin's X coordinate
|
// Grab Mario's current screen position to lock the coin's X coordinate
|
||||||
const marioRect = wrapper.getBoundingClientRect();
|
|
||||||
coin.style.left = `${marioRect.left + 16}px`;
|
coin.style.left = `${marioRect.left + 16}px`;
|
||||||
coin.style.bottom = '35px'; // Adjust for wrapper's bottom offset
|
coin.style.bottom = '35px'; // bottom offset
|
||||||
|
|
||||||
container.appendChild(coin);
|
container.appendChild(coin);
|
||||||
setTimeout(() => coin.remove(), 2000);
|
setTimeout(() => coin.remove(), 2000);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 1000;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: layout paint;
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Matrix || {};
|
const config = window.SeasonalsPluginConfig?.Matrix || {};
|
||||||
|
|
||||||
const enabled = config.EnableMatrix !== undefined ? config.EnableMatrix : true;
|
const enabled = config.EnableMatrix !== undefined ? config.EnableMatrix : true; // enable/disable matrix
|
||||||
const maxTrails = config.SymbolCount || 25;
|
const maxTrails = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of max trails on screen
|
||||||
const backgroundMode = config.EnableMatrixBackground !== undefined ? config.EnableMatrixBackground : false;
|
const backgroundMode = config.EnableMatrixBackground !== undefined ? config.EnableMatrixBackground : false; // enable/disable matrix as background
|
||||||
const matrixChars = config.MatrixChars || '0123456789';
|
const matrixChars = config.MatrixChars !== undefined ? config.MatrixChars : '0123456789'; // characters to use in the matrix rain, default is '0123456789'
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
let isHidden = false;
|
let isHidden = false;
|
||||||
@@ -136,6 +136,7 @@ function createElements() {
|
|||||||
for(let i=0; i<maxTrails; i++) trails.push(new Trail());
|
for(let i=0; i<maxTrails; i++) trails.push(new Trail());
|
||||||
|
|
||||||
function loop() {
|
function loop() {
|
||||||
|
if (!document.body.contains(container)) { clearInterval(window.matrixInterval); return; }
|
||||||
if (isHidden) return; // Pause drawing when hidden
|
if (isHidden) return; // Pause drawing when hidden
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.font = 'bold ' + fontSize + 'px monospace';
|
ctx.font = 'bold ' + fontSize + 'px monospace';
|
||||||
|
|||||||
@@ -12,13 +12,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.oktoberfest-symbol {
|
.oktoberfest-symbol {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10%;
|
top: 0;
|
||||||
font-size: 2.2em;
|
font-size: 2.2em;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
animation-name: oktoberfest-fall, oktoberfest-sway;
|
animation-name: oktoberfest-fall, oktoberfest-sway;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
animation-iteration-count: infinite, infinite;
|
animation-iteration-count: infinite, infinite;
|
||||||
|
translate: 0 -10vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes oktoberfest-fall {
|
@keyframes oktoberfest-fall {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Oktoberfest || {};
|
const config = window.SeasonalsPluginConfig?.Oktoberfest || {};
|
||||||
const oktoberfest = config.EnableOktoberfest !== undefined ? config.EnableOktoberfest : true;
|
const oktoberfest = config.EnableOktoberfest !== undefined ? config.EnableOktoberfest : true; // enable/disable oktoberfest
|
||||||
|
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbols
|
||||||
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of symbols on mobile
|
||||||
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
|
|
||||||
const oktoberfestSymbols = ['🥨', '🍺', '🍻', '🥨', '🥨'];
|
const oktoberfestSymbols = ['🥨', '🍺', '🍻', '🥨', '🥨'];
|
||||||
|
|
||||||
@@ -31,7 +34,6 @@ function toggleOktoberfest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// observe changes in the DOM
|
|
||||||
const observer = new MutationObserver(toggleOktoberfest);
|
const observer = new MutationObserver(toggleOktoberfest);
|
||||||
observer.observe(document.body, {
|
observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
@@ -39,8 +41,8 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
function createOktoberfest(container) {
|
function createOktoberfest(container, count) {
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
const symbol = document.createElement('div');
|
const symbol = document.createElement('div');
|
||||||
symbol.className = 'oktoberfest-symbol';
|
symbol.className = 'oktoberfest-symbol';
|
||||||
symbol.textContent = oktoberfestSymbols[Math.floor(Math.random() * oktoberfestSymbols.length)];
|
symbol.textContent = oktoberfestSymbols[Math.floor(Math.random() * oktoberfestSymbols.length)];
|
||||||
@@ -48,7 +50,9 @@ function createOktoberfest(container) {
|
|||||||
symbol.style.animationDelay = `${Math.random() * 10}s, ${Math.random() * 5}s`;
|
symbol.style.animationDelay = `${Math.random() * 10}s, ${Math.random() * 5}s`;
|
||||||
const duration1 = Math.random() * 5 + 8;
|
const duration1 = Math.random() * 5 + 8;
|
||||||
const duration2 = Math.random() * 3 + 3;
|
const duration2 = Math.random() * 3 + 3;
|
||||||
symbol.style.animationDuration = `${duration1}s, ${duration2}s`;
|
if (enableDifferentDuration) {
|
||||||
|
symbol.style.animationDuration = `${duration1}s, ${duration2}s`;
|
||||||
|
}
|
||||||
|
|
||||||
container.appendChild(symbol);
|
container.appendChild(symbol);
|
||||||
}
|
}
|
||||||
@@ -62,6 +66,10 @@ function initializeOktoberfest() {
|
|||||||
container.setAttribute("aria-hidden", "true");
|
container.setAttribute("aria-hidden", "true");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
createOktoberfest(container);
|
|
||||||
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
const count = !isMobile ? symbolCount : symbolCountMobile;
|
||||||
|
|
||||||
|
createOktoberfest(container, count);
|
||||||
}
|
}
|
||||||
initializeOktoberfest();
|
initializeOktoberfest();
|
||||||
|
|||||||
@@ -12,11 +12,52 @@
|
|||||||
|
|
||||||
.olympia-symbol {
|
.olympia-symbol {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10vh;
|
top: 0;
|
||||||
animation: olympia-fall linear infinite;
|
|
||||||
font-size: 3rem;
|
|
||||||
opacity: 0.95;
|
opacity: 0.95;
|
||||||
text-shadow: 0 0 10px rgba(255,255,255,0.2);
|
text-shadow: 0 0 10px rgba(255,255,255,0.2);
|
||||||
|
z-index: 40;
|
||||||
|
translate: 0 -10vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-flame {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0vh;
|
||||||
|
z-index: 50;
|
||||||
|
pointer-events: none;
|
||||||
|
transform-origin: bottom center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-ring-css {
|
||||||
|
position: relative;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.olympia-ring-css::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
translate: -50% -50%;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border: 5px solid #0081C8; /* Default blue ring */
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.olympia-ring-css[style*="--ring-color"]::before {
|
||||||
|
border-color: var(--ring-color);
|
||||||
|
}
|
||||||
|
.olympia-symbol {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0.95;
|
||||||
|
text-shadow: 0 0 10px rgba(255,255,255,0.2);
|
||||||
|
z-index: 40;
|
||||||
|
translate: 0 -10vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-inner {
|
||||||
|
will-change: transform;
|
||||||
|
display: inline-block;
|
||||||
|
animation: olympia-sway linear infinite alternate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.olympia-symbol img {
|
.olympia-symbol img {
|
||||||
@@ -26,46 +67,76 @@
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.olympia-confetti-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 15;
|
||||||
|
top: 0;
|
||||||
|
will-change: transform;
|
||||||
|
animation-name: olympia-fall;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-confetti-sway {
|
||||||
|
will-change: transform;
|
||||||
|
animation-name: olympia-confetti-sway;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes olympia-confetti-sway {
|
||||||
|
0% { transform: translateX(calc(var(--sway-amount, 50px) * -1)); }
|
||||||
|
100% { transform: translateX(var(--sway-amount, 50px)); }
|
||||||
|
}
|
||||||
|
|
||||||
.olympia-confetti {
|
.olympia-confetti {
|
||||||
position: absolute;
|
|
||||||
top: -5vh;
|
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
opacity: 0.85;
|
background-color: rgb(0, 0, 0);
|
||||||
animation: olympia-confetti-fall linear infinite;
|
will-change: transform;
|
||||||
border-radius: 4px; /* slightly rounder confetti */
|
animation-name: olympia-confetti-flutter;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-confetti.circle {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-confetti.square {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olympia-confetti.triangle {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes olympia-fall {
|
@keyframes olympia-fall {
|
||||||
0% {
|
0% { transform: translateY(-10vh); }
|
||||||
transform: translateY(-10vh) rotate(var(--start-rot, 0deg));
|
100% { transform: translateY(110vh); }
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
85% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(110vh) rotate(var(--end-rot, 360deg));
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes olympia-confetti-fall {
|
@keyframes olympia-sway {
|
||||||
0% {
|
0% { transform: rotate(-25deg) translateX(-20px); }
|
||||||
transform: translateY(-5vh) rotateX(0deg) rotateY(0deg);
|
100% { transform: rotate(25deg) translateX(20px); }
|
||||||
opacity: 0;
|
}
|
||||||
}
|
|
||||||
5% {
|
@keyframes olympia-tumble-3d {
|
||||||
opacity: 1;
|
0% { transform: rotate3d(calc(var(--rot-x) + 0.001), calc(var(--rot-y) + 0.001), calc(var(--rot-z) + 0.001), 0deg); }
|
||||||
}
|
100% { transform: rotate3d(calc(var(--rot-x) + 0.001), calc(var(--rot-y) + 0.001), calc(var(--rot-z) + 0.001), 360deg); }
|
||||||
90% {
|
}
|
||||||
opacity: 1;
|
|
||||||
}
|
@keyframes olympia-confetti-flutter {
|
||||||
100% {
|
0% {
|
||||||
transform: translateY(105vh) rotateX(720deg) rotateY(360deg);
|
transform: rotate3d(var(--rx, 1), var(--ry, 1), var(--rz, 0), 0deg);
|
||||||
opacity: 0;
|
}
|
||||||
}
|
100% {
|
||||||
|
transform: rotate3d(var(--rx, 1), var(--ry, 1), var(--rz, 0), var(--rot-dir, 360deg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,34 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Olympia || {};
|
const config = window.SeasonalsPluginConfig?.Olympia || {};
|
||||||
|
|
||||||
const olympia = config.EnableOlympia !== undefined ? config.EnableOlympia : true;
|
const olympia = config.EnableOlympia !== undefined ? config.EnableOlympia : true; // enable/disable olympia theme
|
||||||
const symbolCount = config.SymbolCount || 25;
|
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of floating symbols
|
||||||
const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 10; // count of floating symbols on mobile
|
||||||
const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
|
||||||
|
// Olympic Ring Colors (Carnival Config)
|
||||||
|
const confettiColors = ['#0081C8', '#FCB131', '#000000', '#00A651', '#EE334E'];
|
||||||
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
const confettiCount = isMobile ? 30 : 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://lottiefiles.com/free-animation/gold-coin-5Spp5kJbLP
|
||||||
|
* https://lottiefiles.com/free-animation/silver-coin-SIgIP59fII
|
||||||
|
* https://lottiefiles.com/free-animation/bronze-coin-wWVCJMsOUq
|
||||||
|
*/
|
||||||
|
const olympicMedals = [
|
||||||
|
"../Seasonals/Resources/olympic_assets/gold_coin.gif",
|
||||||
|
"../Seasonals/Resources/olympic_assets/silver_coin.gif",
|
||||||
|
"../Seasonals/Resources/olympic_assets/bronze_coin.gif"
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://www.flaticon.com/de/kostenloses-icon/fackel_4683293
|
||||||
|
* merged with:
|
||||||
|
* https://lottiefiles.com/free-animation/abstract-flames-lottie-json-animation-oSb0IFoBrj
|
||||||
|
*/
|
||||||
|
const olympicTorch = "../Seasonals/Resources/olympic_assets/torch.gif";
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -49,83 +73,187 @@ function createOlympia() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const standardCount = 15;
|
const standardCount = 15;
|
||||||
const totalSymbols = symbolCount + standardCount;
|
|
||||||
|
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
let finalCount = totalSymbols;
|
let finalCount = isMobile ? symbolCountMobile : symbolCount;
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
finalCount = enableRandomMobile ? totalSymbols : standardCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useRandomDuration = enableDifferentDuration !== false;
|
const useRandomDuration = enableDifferentDuration !== false;
|
||||||
|
|
||||||
const activeItems = ['gold', 'silver', 'bronze', 'torch'];
|
const olympicRings = ['ring_blue.css', 'ring_yellow.css', 'ring_black.css', 'ring_green.css', 'ring_red.css'];
|
||||||
|
const activeItems = [...olympicMedals, ...olympicRings];
|
||||||
|
|
||||||
for (let i = 0; i < finalCount; i++) {
|
for (let i = 0; i < finalCount; i++) {
|
||||||
let symbol = document.createElement('div');
|
let symbol = document.createElement('div');
|
||||||
|
|
||||||
const randomItem = activeItems[Math.floor(Math.random() * activeItems.length)];
|
const randomImgUrl = activeItems[Math.floor(Math.random() * activeItems.length)];
|
||||||
symbol.className = `olympia-symbol olympia-${randomItem}`;
|
const isRing = randomImgUrl.includes('ring_');
|
||||||
|
const isMedal = randomImgUrl.includes('_coin');
|
||||||
|
|
||||||
let img = document.createElement('img');
|
symbol.className = `olympia-symbol`;
|
||||||
img.src = `../Seasonals/Resources/olympia_images/${randomItem}.png`;
|
|
||||||
img.onerror = function() {
|
|
||||||
this.style.display = 'none';
|
|
||||||
this.parentElement.innerHTML = getOlympiaEmojiFallback(randomItem);
|
|
||||||
};
|
|
||||||
symbol.appendChild(img);
|
|
||||||
|
|
||||||
const leftPos = Math.random() * 100;
|
// Create inner div for sway/rotation
|
||||||
const delaySeconds = Math.random() * 10;
|
let innerDiv = document.createElement('div');
|
||||||
|
innerDiv.className = 'olympia-inner';
|
||||||
let durationSeconds = 8;
|
let img = null;
|
||||||
if (useRandomDuration) {
|
|
||||||
durationSeconds = Math.random() * 5 + 6; // 6 to 11 seconds
|
if (isRing) {
|
||||||
|
const colorName = randomImgUrl.split('ring_')[1].split('.')[0];
|
||||||
|
const ringColorMap = {
|
||||||
|
'blue': '#0081C8',
|
||||||
|
'yellow': '#FCB131',
|
||||||
|
'black': '#000000',
|
||||||
|
'green': '#00A651',
|
||||||
|
'red': '#EE334E'
|
||||||
|
};
|
||||||
|
let ringDiv = document.createElement('div');
|
||||||
|
ringDiv.className = 'olympia-ring-css';
|
||||||
|
ringDiv.style.setProperty('--ring-color', ringColorMap[colorName]);
|
||||||
|
innerDiv.appendChild(ringDiv);
|
||||||
|
|
||||||
|
// Add a 3D flip animation for rings
|
||||||
|
const spinReverse = Math.random() > 0.5 ? 'reverse' : 'normal';
|
||||||
|
innerDiv.style.animation = `olympia-tumble-3d ${Math.random() * 4 + 4}s linear infinite ${spinReverse}`;
|
||||||
|
|
||||||
|
// Random 3D Rotation Axis for Tumbling
|
||||||
|
innerDiv.style.setProperty('--rot-x', (Math.random() * 2 - 1).toFixed(2));
|
||||||
|
innerDiv.style.setProperty('--rot-y', (Math.random() * 2 - 1).toFixed(2));
|
||||||
|
innerDiv.style.setProperty('--rot-z', (Math.random() * 2 - 1).toFixed(2));
|
||||||
|
} else {
|
||||||
|
img = document.createElement('img');
|
||||||
|
img.src = randomImgUrl;
|
||||||
|
img.onerror = function() {
|
||||||
|
symbol.remove();
|
||||||
|
};
|
||||||
|
innerDiv.appendChild(img);
|
||||||
|
|
||||||
|
if (isMedal) {
|
||||||
|
innerDiv.style.animation = `olympia-flip-3d ${Math.random() * 4 + 3}s linear infinite`;
|
||||||
|
} else {
|
||||||
|
// Torch sways, medals flip
|
||||||
|
const swayDur = Math.random() * 2 + 2; // 2 to 4s
|
||||||
|
const swayDir = Math.random() > 0.5 ? 'normal' : 'reverse';
|
||||||
|
innerDiv.style.animation = `olympia-sway ${swayDur}s ease-in-out infinite alternate ${swayDir}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const startRot = Math.random() * 360;
|
symbol.appendChild(innerDiv);
|
||||||
symbol.style.setProperty('--start-rot', `${startRot}deg`);
|
|
||||||
symbol.style.setProperty('--end-rot', `${startRot + (Math.random() > 0.5 ? 360 : -360)}deg`);
|
|
||||||
|
|
||||||
symbol.style.left = `${leftPos}vw`;
|
const leftPos = Math.random() * 95;
|
||||||
symbol.style.animationDuration = `${durationSeconds}s`;
|
const delaySeconds = Math.random() * 10;
|
||||||
|
|
||||||
|
// Depth logic for medals and rings
|
||||||
|
const depth = Math.random();
|
||||||
|
const scale = 0.8 + depth * 0.4; // 0.8 to 1.2
|
||||||
|
const zIndex = Math.floor(depth * 30) + 10;
|
||||||
|
|
||||||
|
if (img) {
|
||||||
|
img.style.transform = `scale(${scale})`;
|
||||||
|
} else {
|
||||||
|
innerDiv.firstChild.style.transform = `scale(${scale})`;
|
||||||
|
}
|
||||||
|
symbol.style.zIndex = zIndex;
|
||||||
|
|
||||||
|
let durationSeconds = 8;
|
||||||
|
if (useRandomDuration) {
|
||||||
|
durationSeconds = (1 - depth) * 5 + 6 + Math.random() * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol.style.animation = `olympia-fall ${durationSeconds}s linear infinite`;
|
||||||
symbol.style.animationDelay = `${delaySeconds}s`;
|
symbol.style.animationDelay = `${delaySeconds}s`;
|
||||||
|
symbol.style.left = `${leftPos}vw`;
|
||||||
|
|
||||||
container.appendChild(symbol);
|
container.appendChild(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Olympic Ring Colors
|
// Olympic Torches (Fixed at bottom corners, symmetrically rotated inward)
|
||||||
const confettiColors = ['#0081C8', '#FCB131', '#000000', '#00A651', '#EE334E'];
|
// Generate one random inward rotation (10 to 25 deg) for both to share
|
||||||
const confettiCount = isMobile ? 30 : 60;
|
const sharedTilt = Math.random() * 15 + 10;
|
||||||
|
|
||||||
|
const createTorch = (isLeft) => {
|
||||||
|
const torch = document.createElement('div');
|
||||||
|
torch.className = 'olympia-flame';
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
torch.style.left = '5vw';
|
||||||
|
// Lean right, face normal
|
||||||
|
torch.style.transform = `rotate(${sharedTilt}deg) scaleX(1)`;
|
||||||
|
} else {
|
||||||
|
torch.style.right = '5vw';
|
||||||
|
// Lean left, mirror image
|
||||||
|
torch.style.transform = `rotate(-${sharedTilt}deg) scaleX(-1)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let torchImg = document.createElement('img');
|
||||||
|
torchImg.src = `../Seasonals/Resources/olympic_assets/torch.gif`;
|
||||||
|
torchImg.style.height = '25vh';
|
||||||
|
torchImg.style.objectFit = 'contain';
|
||||||
|
torchImg.onerror = function() {
|
||||||
|
this.style.display = 'none';
|
||||||
|
};
|
||||||
|
torch.appendChild(torchImg);
|
||||||
|
container.appendChild(torch);
|
||||||
|
};
|
||||||
|
|
||||||
|
createTorch(true);
|
||||||
|
createTorch(false);
|
||||||
|
|
||||||
for (let i = 0; i < confettiCount; i++) {
|
for (let i = 0; i < confettiCount; i++) {
|
||||||
|
let wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'olympia-confetti-wrapper';
|
||||||
|
|
||||||
|
let leftPos = Math.random() * 100;
|
||||||
|
wrapper.style.left = `${leftPos}vw`;
|
||||||
|
|
||||||
|
let fallDuration = Math.random() * 3 + 4; // 4 to 7 seconds to fall
|
||||||
|
wrapper.style.animationDuration = `${fallDuration}s`;
|
||||||
|
wrapper.style.animationDelay = `-${Math.random() * fallDuration}s`; // Negative delay so it distributes perfectly immediately
|
||||||
|
|
||||||
|
let swayWrapper = document.createElement('div');
|
||||||
|
swayWrapper.className = 'olympia-confetti-sway';
|
||||||
|
let swayDuration = Math.random() * 2 + 1.5; // 1.5s to 3.5s
|
||||||
|
swayWrapper.style.animationDuration = `${swayDuration}s`;
|
||||||
|
let swayAmount = Math.random() * 30 + 30; // 30px to 60px
|
||||||
|
swayWrapper.style.setProperty('--sway-amount', `${swayAmount}px`);
|
||||||
|
let initSwayDelay = Math.random() * swayDuration;
|
||||||
|
swayWrapper.style.animationDelay = `-${initSwayDelay}s`;
|
||||||
|
|
||||||
let confetti = document.createElement('div');
|
let confetti = document.createElement('div');
|
||||||
confetti.className = 'olympia-confetti';
|
confetti.className = 'olympia-confetti';
|
||||||
|
|
||||||
const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
|
const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
|
||||||
confetti.style.backgroundColor = color;
|
confetti.style.backgroundColor = color;
|
||||||
|
|
||||||
const leftPos = Math.random() * 100;
|
// Random shape
|
||||||
const delaySeconds = Math.random() * 8;
|
const shape = Math.random();
|
||||||
const duration = Math.random() * 3 + 5;
|
if (shape > 0.66) {
|
||||||
|
confetti.classList.add('circle');
|
||||||
|
const size = Math.random() * 5 + 5;
|
||||||
|
confetti.style.width = `${size}px`;
|
||||||
|
confetti.style.height = `${size}px`;
|
||||||
|
} else if (shape > 0.33) {
|
||||||
|
confetti.classList.add('rect');
|
||||||
|
const width = Math.random() * 4 + 4;
|
||||||
|
const height = Math.random() * 5 + 8;
|
||||||
|
confetti.style.width = `${width}px`;
|
||||||
|
confetti.style.height = `${height}px`;
|
||||||
|
} else {
|
||||||
|
confetti.classList.add('triangle');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random 3D Rotation for flutter
|
||||||
|
confetti.style.setProperty('--rx', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--ry', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--rz', (Math.random() * 0.5).toFixed(2));
|
||||||
|
confetti.style.setProperty('--rot-dir', `${(Math.random() > 0.5 ? 1 : -1) * 360}deg`);
|
||||||
|
let rotateDuration = Math.random() * 0.8 + 0.4;
|
||||||
|
confetti.style.animationDuration = `${rotateDuration}s`;
|
||||||
|
|
||||||
confetti.style.left = `${leftPos}vw`;
|
swayWrapper.appendChild(confetti);
|
||||||
confetti.style.animationDuration = `${duration}s`;
|
wrapper.appendChild(swayWrapper);
|
||||||
confetti.style.animationDelay = `${delaySeconds}s`;
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
container.appendChild(confetti);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOlympiaEmojiFallback(type) {
|
|
||||||
if (type === 'gold') return '🥇';
|
|
||||||
if (type === 'silver') return '🥈';
|
|
||||||
if (type === 'bronze') return '🥉';
|
|
||||||
if (type === 'torch') return '🔥';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeOlympia() {
|
function initializeOlympia() {
|
||||||
if (!olympia) return;
|
if (!olympia) return;
|
||||||
createOlympia();
|
createOlympia();
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 58 KiB |
@@ -6,7 +6,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 10; /* Behind popups but over background */
|
z-index: 10;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -30,8 +30,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.oscar-spotlight {
|
.oscar-spotlight {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10vh;
|
top: 0;
|
||||||
/* MARK: SPOTLIGHT WIDTH CONFIGURATION */
|
/* MARK: SPOTLIGHT WIDTH CONFIGURATION */
|
||||||
/* To adjust bottom width (spread), change 'width' property (e.g., 20vw for narrow, 40vw for wide). */
|
/* To adjust bottom width (spread), change 'width' property (e.g., 20vw for narrow, 40vw for wide). */
|
||||||
/* To adjust top width (origin), modify first two percentages in 'clip-path' (e.g., 48% 0, 52% 0 for a very thin start). */
|
/* To adjust top width (origin), modify first two percentages in 'clip-path' (e.g., 48% 0, 52% 0 for a very thin start). */
|
||||||
@@ -42,9 +43,11 @@
|
|||||||
transform-origin: top center;
|
transform-origin: top center;
|
||||||
animation: spotlight-sweep 12s infinite alternate ease-in-out;
|
animation: spotlight-sweep 12s infinite alternate ease-in-out;
|
||||||
mix-blend-mode: screen;
|
mix-blend-mode: screen;
|
||||||
|
translate: 0 -10vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oscar-flash {
|
.oscar-flash {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Oscar || {};
|
const config = window.SeasonalsPluginConfig?.Oscar || {};
|
||||||
const oscar = config.EnableOscar !== undefined ? config.EnableOscar : true;
|
const oscar = config.EnableOscar !== undefined ? config.EnableOscar : true; // enable/disable oscar
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -56,9 +56,9 @@ function createOscar(container) {
|
|||||||
container.appendChild(carpet);
|
container.appendChild(carpet);
|
||||||
container.appendChild(spotlights);
|
container.appendChild(spotlights);
|
||||||
|
|
||||||
// Paparazzi flashes with randomized intervals
|
|
||||||
function flashLoop() {
|
function flashLoop() {
|
||||||
if (!document.querySelector('.oscar-container')) {
|
if (!document.body.contains(container)) return; // Kill the loop if container is removed
|
||||||
|
if (container.style.display === 'none') {
|
||||||
setTimeout(flashLoop, 1000); // Check again later if hidden
|
setTimeout(flashLoop, 1000); // Check again later if hidden
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 9999;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: layout paint;
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
// 1. Read Configuration
|
|
||||||
const config = window.SeasonalsPluginConfig?.Pride || {};
|
const config = window.SeasonalsPluginConfig?.Pride || {};
|
||||||
|
|
||||||
const enabled = config.EnablePride !== undefined ? config.EnablePride : true;
|
const enabled = config.EnablePride !== undefined ? config.EnablePride : true; // enable/disable pride
|
||||||
const elementCount = config.HeartCount || 20;
|
const elementCount = config.HeartCount !== undefined ? config.HeartCount : 20; // count of heart
|
||||||
const heartSize = config.HeartSize || 1.5;
|
const heartSize = config.HeartSize !== undefined ? config.HeartSize : 1.5; // size of hearts
|
||||||
const colorHeader = config.ColorHeader !== undefined ? config.ColorHeader : true;
|
const colorHeader = config.ColorHeader !== undefined ? config.ColorHeader : true; // optionally color the header with pride colors
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
// 2. Toggle Function
|
|
||||||
// Hides the effect when a video player, trailer (in full width mode), dashboard, or user menu is active.
|
|
||||||
function togglePride() {
|
function togglePride() {
|
||||||
const container = document.querySelector('.pride-container');
|
const container = document.querySelector('.pride-container');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
@@ -34,8 +31,6 @@ function togglePride() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. MutationObserver
|
|
||||||
// Watches the DOM for changes so the effect can auto-hide/show.
|
|
||||||
const observer = new MutationObserver(togglePride);
|
const observer = new MutationObserver(togglePride);
|
||||||
observer.observe(document.body, {
|
observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
@@ -43,8 +38,6 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4. Element Creation
|
|
||||||
// Create and append your animated elements to the container.
|
|
||||||
function createElements() {
|
function createElements() {
|
||||||
const container = document.querySelector('.pride-container') || document.createElement('div');
|
const container = document.querySelector('.pride-container') || document.createElement('div');
|
||||||
|
|
||||||
@@ -82,7 +75,6 @@ function createElements() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Initialization
|
|
||||||
function initializePride() {
|
function initializePride() {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
createElements();
|
createElements();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Rain || {};
|
const config = window.SeasonalsPluginConfig?.Rain || {};
|
||||||
|
|
||||||
const enabled = config.EnableRain !== undefined ? config.EnableRain : true;
|
const enabled = config.EnableRain !== undefined ? config.EnableRain : true; // enable/disable rain
|
||||||
const isMobile = window.innerWidth <= 768;
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300);
|
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops
|
||||||
const rainSpeed = config.RainSpeed || 1.0;
|
const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,68 +1,66 @@
|
|||||||
.resurrection-container {
|
.resurrection-container {
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
contain: layout paint;
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resurrection-symbol {
|
.resurrection-symbol {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
top: 0;
|
top: 0;
|
||||||
translate: 0 -15vh;
|
translate: 0 -15vh;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
cursor: default;
|
||||||
cursor: default;
|
animation-name: resurrection-fall;
|
||||||
animation-name: resurrection-fall;
|
animation-timing-function: linear;
|
||||||
animation-timing-function: linear;
|
animation-iteration-count: infinite;
|
||||||
animation-iteration-count: infinite;
|
will-change: transform;
|
||||||
will-change: transform;
|
}
|
||||||
}
|
|
||||||
|
.resurrection-sway-wrapper {
|
||||||
.resurrection-sway-wrapper {
|
will-change: transform;
|
||||||
will-change: transform;
|
animation-name: resurrection-sway;
|
||||||
animation-name: resurrection-sway;
|
animation-timing-function: ease-in-out;
|
||||||
animation-timing-function: ease-in-out;
|
animation-iteration-count: infinite;
|
||||||
animation-iteration-count: infinite;
|
}
|
||||||
}
|
|
||||||
|
.resurrection-symbol img {
|
||||||
.resurrection-symbol img {
|
z-index: 15;
|
||||||
z-index: 15;
|
height: auto;
|
||||||
height: auto;
|
width: 56px;
|
||||||
width: 56px;
|
opacity: 0.95;
|
||||||
opacity: 0.95;
|
filter: drop-shadow(0 0 8px rgba(255, 215, 130, 0.5));
|
||||||
filter: drop-shadow(0 0 8px rgba(255, 215, 130, 0.5));
|
}
|
||||||
}
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
@media (max-width: 768px) {
|
.resurrection-symbol img {
|
||||||
.resurrection-symbol img {
|
width: 42px;
|
||||||
width: 42px;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@keyframes resurrection-fall {
|
||||||
@keyframes resurrection-fall {
|
0% {
|
||||||
0% {
|
transform: translate3d(0, -15vh, 0);
|
||||||
transform: translate3d(0, -15vh, 0);
|
}
|
||||||
}
|
|
||||||
|
100% {
|
||||||
100% {
|
transform: translate3d(0, 105vh, 0);
|
||||||
transform: translate3d(0, 105vh, 0);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@keyframes resurrection-sway {
|
||||||
@keyframes resurrection-sway {
|
0%,
|
||||||
0%,
|
100% {
|
||||||
100% {
|
transform: translateX(0);
|
||||||
transform: translateX(0);
|
}
|
||||||
}
|
|
||||||
|
50% {
|
||||||
50% {
|
transform: translateX(65px);
|
||||||
transform: translateX(65px);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Resurrection || {};
|
const config = window.SeasonalsPluginConfig?.Resurrection || {};
|
||||||
|
|
||||||
const enableResurrection = config.EnableResurrection !== undefined ? config.EnableResurrection : true;
|
const enableResurrection = config.EnableResurrection !== undefined ? config.EnableResurrection : true; // enable/disable resurrection
|
||||||
const enableRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableRandomSymbolsMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 12; // count of symbols
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 5; // count of symbols on mobile
|
||||||
const symbolCount = config.SymbolCount || 12;
|
|
||||||
|
|
||||||
let animationEnabled = true;
|
let animationEnabled = true;
|
||||||
let statusLogged = false;
|
let statusLogged = false;
|
||||||
@@ -78,20 +77,17 @@ function createSymbol(imageSrc, leftPercent, delaySeconds) {
|
|||||||
|
|
||||||
function addSymbols(count) {
|
function addSymbols(count) {
|
||||||
const container = document.querySelector('.resurrection-container');
|
const container = document.querySelector('.resurrection-container');
|
||||||
if (!container || !enableRandomSymbols) return;
|
if (!container) return;
|
||||||
|
|
||||||
const isDesktop = window.innerWidth > 768;
|
|
||||||
if (!isDesktop && !enableRandomSymbolsMobile) return;
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
const imageSrc = images[Math.floor(Math.random() * images.length)];
|
const imageSrc = images[Math.floor(Math.random() * images.length)];
|
||||||
const left = Math.random() * 100;
|
const left = Math.random() * 100;
|
||||||
const delay = Math.random() * 12;
|
const delay = -(Math.random() * 12);
|
||||||
container.appendChild(createSymbol(imageSrc, left, delay));
|
container.appendChild(createSymbol(imageSrc, left, delay));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initResurrection() {
|
function initResurrection(count) {
|
||||||
let container = document.querySelector('.resurrection-container');
|
let container = document.querySelector('.resurrection-container');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = document.createElement('div');
|
container = document.createElement('div');
|
||||||
@@ -103,17 +99,21 @@ function initResurrection() {
|
|||||||
// Place one of each of the 8 provided resurrection images first.
|
// Place one of each of the 8 provided resurrection images first.
|
||||||
images.forEach((imageSrc, index) => {
|
images.forEach((imageSrc, index) => {
|
||||||
const left = (index + 1) * (100 / (images.length + 1));
|
const left = (index + 1) * (100 / (images.length + 1));
|
||||||
const delay = Math.random() * 8;
|
const delay = -(Math.random() * 8);
|
||||||
container.appendChild(createSymbol(imageSrc, left, delay));
|
container.appendChild(createSymbol(imageSrc, left, delay));
|
||||||
});
|
});
|
||||||
|
|
||||||
const extraCount = Math.max(symbolCount - images.length, 0);
|
const extraCount = Math.max(count - images.length, 0);
|
||||||
addSymbols(extraCount);
|
addSymbols(extraCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeResurrection() {
|
function initializeResurrection() {
|
||||||
if (!enableResurrection) return;
|
if (!enableResurrection) return;
|
||||||
initResurrection();
|
|
||||||
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
const count = !isMobile ? symbolCount : symbolCountMobile;
|
||||||
|
|
||||||
|
initResurrection(count);
|
||||||
toggleResurrection();
|
toggleResurrection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Santa || {};
|
const config = window.SeasonalsPluginConfig?.Santa || {};
|
||||||
|
|
||||||
const santaIsFlying = config.EnableSanta !== undefined ? config.EnableSanta : true; // enable/disable santa
|
const santaIsFlying = config.EnableSanta !== undefined ? config.EnableSanta : true; // enable/disable santa
|
||||||
let snowflakesCount = config.SnowflakesCount || 500; // count of snowflakes (recommended values: 300-600)
|
let snowflakesCount = config.SnowflakesCount !== undefined ? config.SnowflakesCount : 500; // count of snowflakes
|
||||||
const snowflakesCountMobile = config.SnowflakesCountMobile || 250; // count of snowflakes on mobile devices (Warning: High values may affect performance)
|
const snowflakesCountMobile = config.SnowflakesCountMobile !== undefined ? config.SnowflakesCountMobile : 250; // count of snowflakes on mobile
|
||||||
const snowFallSpeed = config.SnowFallSpeed || 3; // speed of snowfall (recommended values: 0-5)
|
const snowFallSpeed = config.SnowFallSpeed !== undefined ? config.SnowFallSpeed : 3; // speed of snowfall
|
||||||
const santaSpeed = config.SantaSpeed || 10; // speed of santa in seconds (recommended values: 5-15)
|
const santaSpeed = config.SantaSpeed !== undefined ? config.SantaSpeed : 10; // speed of santa in seconds
|
||||||
const santaSpeedMobile = config.SantaSpeedMobile || 8; // speed of santa on mobile devices in seconds
|
const santaSpeedMobile = config.SantaSpeedMobile !== undefined ? config.SantaSpeedMobile : 8; // speed of santa on mobile devices in seconds
|
||||||
const maxSantaRestTime = config.MaxSantaRestTime || 8; // maximum time santa rests in seconds
|
const maxSantaRestTime = config.MaxSantaRestTime !== undefined ? config.MaxSantaRestTime : 8; // maximum time santa rests in seconds
|
||||||
const minSantaRestTime = config.MinSantaRestTime || 3; // minimum time santa rests in seconds
|
const minSantaRestTime = config.MinSantaRestTime !== undefined ? config.MinSantaRestTime : 3; // minimum time santa rests in seconds
|
||||||
const maxPresentFallSpeed = config.MaxPresentFallSpeed || 5; // maximum speed of falling presents in seconds
|
const maxPresentFallSpeed = config.MaxPresentFallSpeed !== undefined ? config.MaxPresentFallSpeed : 5; // maximum speed of falling presents in seconds
|
||||||
const minPresentFallSpeed = config.MinPresentFallSpeed || 2; // minimum speed of falling presents in seconds
|
const minPresentFallSpeed = config.MinPresentFallSpeed !== undefined ? config.MinPresentFallSpeed : 2; // minimum speed of falling presents in seconds
|
||||||
|
|
||||||
// credits: flaticon.com
|
// credits: flaticon.com
|
||||||
const presentImages = [
|
const presentImages = [
|
||||||
@@ -238,7 +238,7 @@ function animateSanta() {
|
|||||||
function startAnimation() {
|
function startAnimation() {
|
||||||
const santaHeight = santa.offsetHeight;
|
const santaHeight = santa.offsetHeight;
|
||||||
if (santaHeight === 0) {
|
if (santaHeight === 0) {
|
||||||
setTimeout(startAnimation, 100);
|
setTimeout(() => { if (document.body.contains(santa)) startAnimation(); }, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// console.log('Santa height: ', santaHeight);
|
// console.log('Santa height: ', santaHeight);
|
||||||
@@ -283,7 +283,7 @@ function animateSanta() {
|
|||||||
animationFrameIdSanta = requestAnimationFrame(move);
|
animationFrameIdSanta = requestAnimationFrame(move);
|
||||||
} else {
|
} else {
|
||||||
const pause = Math.random() * ((maxSantaRestTime - minSantaRestTime) * 1000) + minSantaRestTime * 1000;
|
const pause = Math.random() * ((maxSantaRestTime - minSantaRestTime) * 1000) + minSantaRestTime * 1000;
|
||||||
setTimeout(animateSanta, pause);
|
setTimeout(() => { if (document.body.contains(santa)) animateSanta(); }, pause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +310,8 @@ function initializeSanta() {
|
|||||||
}
|
}
|
||||||
const container = document.querySelector('.santa-container');
|
const container = document.querySelector('.santa-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches; // check if mobile device
|
||||||
if (screenWidth < 768) { // lower count of snowflakes on mobile devices
|
if (isMobile) { // lower count of snowflakes on mobile devices
|
||||||
isMobile = true;
|
isMobile = true;
|
||||||
console.log('Mobile device detected. Reducing snowflakes count.');
|
console.log('Mobile device detected. Reducing snowflakes count.');
|
||||||
snowflakesCount = snowflakesCountMobile;
|
snowflakesCount = snowflakesCountMobile;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Snowfall || {};
|
const config = window.SeasonalsPluginConfig?.Snowfall || {};
|
||||||
|
|
||||||
const snowfall = config.EnableSnowfall !== undefined ? config.EnableSnowfall : true; // enable/disable snowfall
|
const snowfall = config.EnableSnowfall !== undefined ? config.EnableSnowfall : true; // enable/disable snowfall
|
||||||
let snowflakesCount = config.SnowflakesCount || 500; // count of snowflakes (recommended values: 300-600)
|
let snowflakesCount = config.SnowflakesCount !== undefined ? config.SnowflakesCount : 500; // count of snowflakes
|
||||||
const snowflakesCountMobile = config.SnowflakesCountMobile || 250; // count of snowflakes on mobile devices (Warning: High values may affect performance)
|
const snowflakesCountMobile = config.SnowflakesCountMobile !== undefined ? config.SnowflakesCountMobile : 250; // count of snowflakes on mobile
|
||||||
const snowFallSpeed = config.Speed || 3; // speed of snowfall (recommended values: 0-5)
|
const snowFallSpeed = config.Speed !== undefined ? config.Speed : 3; // speed of snowfall
|
||||||
|
|
||||||
let msgPrinted = false; // flag to prevent multiple console messages
|
let msgPrinted = false; // flag to prevent multiple console messages
|
||||||
|
|
||||||
@@ -181,8 +181,8 @@ function initializeSnowfall() {
|
|||||||
}
|
}
|
||||||
const container = document.querySelector('.snowfall-container');
|
const container = document.querySelector('.snowfall-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches; // check if mobile device
|
||||||
if (screenWidth < 768) { // lower count of snowflakes on mobile devices
|
if (isMobile) { // lower count of snowflakes on mobile devices
|
||||||
console.log('Mobile device detected. Reducing snowflakes count.');
|
console.log('Mobile device detected. Reducing snowflakes count.');
|
||||||
snowflakesCount = snowflakesCountMobile;
|
snowflakesCount = snowflakesCountMobile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,39 +22,14 @@
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
text-shadow: 0 0 5px #000;
|
text-shadow: 0 0 5px #000;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
-webkit-animation-name: heart-fall, heart-shake;
|
|
||||||
-webkit-animation-duration: 12s, 3s;
|
|
||||||
-webkit-animation-timing-function: linear, ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite, infinite;
|
|
||||||
animation-name: snowflakes-fall, snowflakes-shake;
|
animation-name: snowflakes-fall, snowflakes-shake;
|
||||||
animation-duration: 12s, 3s;
|
animation-duration: 12s, 3s;
|
||||||
animation-timing-function: linear, ease-in-out;
|
animation-timing-function: linear, ease-in-out;
|
||||||
animation-iteration-count: infinite, infinite;
|
animation-iteration-count: infinite, infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes snowflakes-fall {
|
|
||||||
0% {
|
|
||||||
translate: 0 -10vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
translate: 0 110vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes snowflakes-shake {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: translateX(80px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes snowflakes-fall {
|
@keyframes snowflakes-fall {
|
||||||
0% {
|
0% {
|
||||||
@@ -76,64 +51,4 @@
|
|||||||
50% {
|
50% {
|
||||||
transform: translateX(80px);
|
transform: translateX(80px);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(0) {
|
|
||||||
left: 0%;
|
|
||||||
animation-delay: 0s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(1) {
|
|
||||||
left: 10%;
|
|
||||||
animation-delay: 1s, 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(2) {
|
|
||||||
left: 20%;
|
|
||||||
animation-delay: 6s, 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(3) {
|
|
||||||
left: 30%;
|
|
||||||
animation-delay: 4s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(4) {
|
|
||||||
left: 40%;
|
|
||||||
animation-delay: 2s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(5) {
|
|
||||||
left: 50%;
|
|
||||||
animation-delay: 8s, 3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(6) {
|
|
||||||
left: 60%;
|
|
||||||
animation-delay: 6s, 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(7) {
|
|
||||||
left: 70%;
|
|
||||||
animation-delay: 2.5s, 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(8) {
|
|
||||||
left: 80%;
|
|
||||||
animation-delay: 1s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(9) {
|
|
||||||
left: 90%;
|
|
||||||
animation-delay: 3s, 1.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(10) {
|
|
||||||
left: 25%;
|
|
||||||
animation-delay: 2s, 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snowflake:nth-of-type(11) {
|
|
||||||
left: 65%;
|
|
||||||
animation-delay: 4s, 2.5s;
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Snowflakes || {};
|
const config = window.SeasonalsPluginConfig?.Snowflakes || {};
|
||||||
|
|
||||||
const snowflakes = config.EnableSnowflakes !== undefined ? config.EnableSnowflakes : true; // enable/disable snowflakes
|
const snowflakes = config.EnableSnowflakes !== undefined ? config.EnableSnowflakes : true; // enable/disable snowflakes
|
||||||
const randomSnowflakes = config.EnableRandomSnowflakes !== undefined ? config.EnableRandomSnowflakes : true; // enable random Snowflakes
|
const snowflakeCount = config.SnowflakeCount !== undefined ? config.SnowflakeCount : 25; // count of snowflakes
|
||||||
const randomSnowflakesMobile = config.EnableRandomSnowflakesMobile !== undefined ? config.EnableRandomSnowflakesMobile : false; // enable random Snowflakes on mobile devices
|
const snowflakeCountMobile = config.SnowflakeCountMobile !== undefined ? config.SnowflakeCountMobile : 10; // count of snowflakes on mobile
|
||||||
const enableColoredSnowflakes = config.EnableColoredSnowflakes !== undefined ? config.EnableColoredSnowflakes : true; // enable colored snowflakes
|
const enableColoredSnowflakes = config.EnableColoredSnowflakes !== undefined ? config.EnableColoredSnowflakes : true; // enable/disable colored snowflakes
|
||||||
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different animation duration
|
const enableDiffrentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const snowflakeCount = config.SnowflakeCount || 25; // count of random extra snowflakes
|
|
||||||
|
|
||||||
const snowflakeSymbols = ['❅', '❆']; // some snowflake symbols
|
const snowflakeSymbols = ['❅', '❆']; // some snowflake symbols
|
||||||
const snowflakeSymbolsMobile = ['❅', '❆', '❄']; // some snowflake symbols mobile version
|
const snowflakeSymbolsMobile = ['❅', '❆', '❄']; // some snowflake symbols mobile version
|
||||||
@@ -46,11 +45,16 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
function addRandomSnowflakes(count) {
|
function initSnowflakes(count) {
|
||||||
const snowflakeContainer = document.querySelector('.snowflakes'); // get the snowflake container
|
let snowflakeContainer = document.querySelector('.snowflakes'); // get the snowflake container
|
||||||
if (!snowflakeContainer) return; // exit if snowflake container is not found
|
if (!snowflakeContainer) {
|
||||||
|
snowflakeContainer = document.createElement("div");
|
||||||
|
snowflakeContainer.className = "snowflakes";
|
||||||
|
snowflakeContainer.setAttribute("aria-hidden", "true");
|
||||||
|
document.body.appendChild(snowflakeContainer);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Adding random snowflakes');
|
console.log('Adding snowflakes');
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// create a new snowflake element
|
// create a new snowflake element
|
||||||
@@ -66,7 +70,7 @@ function addRandomSnowflakes(count) {
|
|||||||
|
|
||||||
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
// set random horizontal position, animation delay and size(uncomment lines to enable)
|
||||||
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
const randomLeft = Math.random() * 100; // position (0% to 100%)
|
||||||
const randomAnimationDelay = Math.random() * 8; // delay (0s to 8s)
|
const randomAnimationDelay = -(Math.random() * 14); // delay (-14s to 0s)
|
||||||
const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
|
const randomAnimationDelay2 = -(Math.random() * 5); // delay (-5s to 0s)
|
||||||
|
|
||||||
// apply styles
|
// apply styles
|
||||||
@@ -83,49 +87,18 @@ function addRandomSnowflakes(count) {
|
|||||||
// add the snowflake to the container
|
// add the snowflake to the container
|
||||||
snowflakeContainer.appendChild(snowflake);
|
snowflakeContainer.appendChild(snowflake);
|
||||||
}
|
}
|
||||||
console.log('Random snowflakes added');
|
console.log('Snowflakes added');
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize standard snowflakes
|
// initialize snowflakes
|
||||||
function initSnowflakes() {
|
|
||||||
const snowflakesContainer = document.querySelector('.snowflakes') || document.createElement("div");
|
|
||||||
|
|
||||||
if (!document.querySelector('.snowflakes')) {
|
|
||||||
snowflakesContainer.className = "snowflakes";
|
|
||||||
snowflakesContainer.setAttribute("aria-hidden", "true");
|
|
||||||
document.body.appendChild(snowflakesContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array of snowflake characters
|
|
||||||
const snowflakeSymbols = ['❅', '❆'];
|
|
||||||
|
|
||||||
// create the 12 standard snowflakes
|
|
||||||
for (let i = 0; i < 12; i++) {
|
|
||||||
const snowflake = document.createElement('div');
|
|
||||||
snowflake.className = 'snowflake';
|
|
||||||
snowflake.textContent = snowflakeSymbols[i % 2]; // change between ❅ and ❆
|
|
||||||
|
|
||||||
// set random animation duration
|
|
||||||
if (enableDiffrentDuration) {
|
|
||||||
const randomAnimationDuration = Math.random() * 14 + 10; // delay (10s to 14s)
|
|
||||||
const randomAnimationDuration2 = Math.random() * 5 + 3; // delay (3s to 5s)
|
|
||||||
snowflake.style.animationDuration = `${randomAnimationDuration}s, ${randomAnimationDuration2}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
snowflakesContainer.appendChild(snowflake);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize snowflakes and add random snowflakes
|
|
||||||
function initializeSnowflakes() {
|
function initializeSnowflakes() {
|
||||||
if (!snowflakes) return; // exit if snowflakes are disabled
|
if (!snowflakes) return; // exit if snowflakes are disabled
|
||||||
initSnowflakes();
|
|
||||||
toggleSnowflakes();
|
|
||||||
|
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (randomSnowflakes && (screenWidth > 768 || randomSnowflakesMobile)) { // add random snowflakes only on larger screens, unless enabled for mobile devices
|
const count = !isMobile ? snowflakeCount : snowflakeCountMobile;
|
||||||
addRandomSnowflakes(snowflakeCount);
|
|
||||||
}
|
initSnowflakes(count);
|
||||||
|
toggleSnowflakes();
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeSnowflakes();
|
initializeSnowflakes();
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Snowstorm || {};
|
const config = window.SeasonalsPluginConfig?.Snowstorm || {};
|
||||||
|
|
||||||
const snowstorm = config.enableSnowstorm !== undefined ? config.EnableSnowstorm : true; // enable/disable snowstorm
|
const snowstorm = config.EnableSnowstorm !== undefined ? config.EnableSnowstorm : true; // enable/disable snowstorm
|
||||||
let snowflakesCount = config.SnowflakesCount || 500; // count of snowflakes (recommended values: 300-600)
|
let snowflakesCount = config.SnowflakesCount !== undefined ? config.SnowflakesCount : 500; // count of snowflakes
|
||||||
const snowflakesCountMobile = config.SnowflakesCountMobile || 250; // count of snowflakes on mobile devices (Warning: High values may affect performance)
|
const snowflakesCountMobile = config.SnowflakesCountMobile !== undefined ? config.SnowflakesCountMobile : 250; // count of snowflakes on mobile
|
||||||
const snowFallSpeed = config.Speed || 6; // speed of snowfall (recommended values: 4-8)
|
const snowFallSpeed = config.Speed !== undefined ? config.Speed : 6; // speed of snowstorm
|
||||||
const horizontalWind = config.HorizontalWind || 4; // horizontal wind speed (recommended value: 4)
|
const horizontalWind = config.HorizontalWind !== undefined ? config.HorizontalWind : 4; // horizontal wind strength
|
||||||
const verticalVariation = config.VerticalVariation || 2; // vertical variation (recommended value: 2)
|
const verticalVariation = config.VerticalVariation !== undefined ? config.VerticalVariation : 2; // vertical variation
|
||||||
|
|
||||||
let msgPrinted = false; // flag to prevent multiple console messages
|
let msgPrinted = false; // flag to prevent multiple console messages
|
||||||
|
|
||||||
@@ -184,8 +184,8 @@ function initializeSnowstorm() {
|
|||||||
}
|
}
|
||||||
const container = document.querySelector('.snowstorm-container');
|
const container = document.querySelector('.snowstorm-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
const screenWidth = window.innerWidth; // get the screen width to detect mobile devices
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
if (screenWidth < 768) { // lower count of snowflakes on mobile devices
|
if (isMobile) { // lower count of snowflakes on mobile devices
|
||||||
console.log('Mobile device detected. Reducing snowflakes count.');
|
console.log('Mobile device detected. Reducing snowflakes count.');
|
||||||
snowflakesCount = snowflakesCountMobile;
|
snowflakesCount = snowflakesCountMobile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,54 +5,97 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 9999;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-bg-glow {
|
||||||
|
will-change: transform;
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; width: 100vw; height: 100vh;
|
||||||
|
background: radial-gradient(circle at 70% 30%, rgba(138, 43, 226, 0.15), transparent 60%),
|
||||||
|
radial-gradient(circle at 20% 80%, rgba(65, 105, 225, 0.15), transparent 50%);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
animation: space-nebula-pulse 10s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes space-nebula-pulse {
|
||||||
|
0% { opacity: 0.6; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-starfield {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; width: 100vw; height: 100vh;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-shooting-star {
|
||||||
|
will-change: opacity;
|
||||||
|
position: absolute;
|
||||||
|
width: 250px;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: space-shoot 25s linear infinite;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes space-shoot {
|
||||||
|
0% { transform: rotate(var(--shoot-angle)) translateX(0); opacity: 0; }
|
||||||
|
5% { opacity: 1; }
|
||||||
|
35% { opacity: 1; }
|
||||||
|
40% { transform: rotate(var(--shoot-angle)) translateX(var(--shoot-distance)); opacity: 0; }
|
||||||
|
100% { transform: rotate(var(--shoot-angle)) translateX(var(--shoot-distance)); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
.space-symbol {
|
.space-symbol {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
animation-iteration-count: infinite;
|
animation-iteration-count: infinite;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
z-index: 9999;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-symbol img {
|
.space-symbol img {
|
||||||
|
will-change: transform;
|
||||||
width: 6vh;
|
width: 6vh;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-width: 60px;
|
max-width: 60px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
/* Add a slow spin to images */
|
|
||||||
animation: space-slow-spin var(--rot-dur, 20s) linear infinite;
|
animation: space-slow-spin var(--rot-dur, 20s) linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Specific elements scaling */
|
/* Specific elements scaling */
|
||||||
.space-planet1, .space-planet2 { font-size: 4rem; }
|
.space-planet img { width: 8vh; max-width: 80px; }
|
||||||
.space-planet1 img, .space-planet2 img { width: 8vh; max-width: 80px; }
|
.space-astronaut img { width: 10vh; max-width: 100px; }
|
||||||
.space-star { font-size: 2rem; opacity: 0.6; }
|
.space-satellite img { width: 12vh; max-width: 120px; }
|
||||||
.space-star img { width: 3vh; max-width: 30px; }
|
.space-iss img { width: 25vh; max-width: 180px; }
|
||||||
|
.space-rocket img { width: 12vh; max-width: 120px; }
|
||||||
|
|
||||||
@keyframes space-drift-right {
|
@keyframes space-drift-right {
|
||||||
0% {
|
0% { transform: translateX(-10vw) translateY(0) scaleX(-1); }
|
||||||
transform: translateX(0) scaleX(-1);
|
50% { transform: translateX(60vw) translateY(-30vh) scaleX(-1); }
|
||||||
}
|
100% { transform: translateX(140vw) translateY(0) scaleX(-1); }
|
||||||
100% {
|
|
||||||
transform: translateX(120vw) scaleX(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes space-drift-left {
|
@keyframes space-drift-left {
|
||||||
0% {
|
0% { transform: translateX(10vw) translateY(0); }
|
||||||
transform: translateX(0);
|
50% { transform: translateX(-60vw) translateY(30vh); }
|
||||||
}
|
100% { transform: translateX(-140vw) translateY(0); }
|
||||||
100% {
|
|
||||||
transform: translateX(-120vw);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes space-slow-spin {
|
@keyframes space-slow-spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% { transform: rotate(0deg); }
|
||||||
100% { transform: rotate(360deg); }
|
100% { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes space-star-drift {
|
||||||
|
from { transform: translateY(0); }
|
||||||
|
to { transform: translateY(-100vh); }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,50 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Space || {};
|
const config = window.SeasonalsPluginConfig?.Space || {};
|
||||||
|
|
||||||
const space = config.EnableSpace !== undefined ? config.EnableSpace : true;
|
const space = config.EnableSpace !== undefined ? config.EnableSpace : true; // enable/disable space
|
||||||
const symbolCount = config.SymbolCount || 25;
|
const planetCountConf = config.PlanetCount !== undefined ? config.PlanetCount : 6; // count of planets
|
||||||
const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const astronautCountConf = config.AstronautCount !== undefined ? config.AstronautCount : 1; // count of astronaut
|
||||||
const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const satelliteCountConf = config.SatelliteCount !== undefined ? config.SatelliteCount : 4; // count of satellite
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const issCountConf = config.IssCount !== undefined ? config.IssCount : 1; // count of iss
|
||||||
|
const rocketCountConf = config.RocketCount !== undefined ? config.RocketCount : 1; // count of rocket/space shuttle
|
||||||
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 2; // Devisor to reduce number of objects on mobile
|
||||||
|
|
||||||
|
// Credit: https://lottiefiles.com/free-animation/astronaut-63lcWG4Xnh
|
||||||
|
const astronautImages = [
|
||||||
|
"../Seasonals/Resources/space_assets/astronaut_1.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Credits: https://flaticon.com
|
||||||
|
const planetImages = [
|
||||||
|
"../Seasonals/Resources/space_assets/planet_1.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_2.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_3.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_4.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_5.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_6.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_7.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_8.png",
|
||||||
|
"../Seasonals/Resources/space_assets/planet_9.png"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Credits: https://lottiefiles.com/free-animation/s-satellite-vfnNE8AALo
|
||||||
|
const satelliteImages = [
|
||||||
|
"../Seasonals/Resources/space_assets/Satellite_1.gif",
|
||||||
|
"../Seasonals/Resources/space_assets/Satellite_2.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Credit: https://pixabay.com/de/illustrations/raumstation-raum-struktur-8023777/
|
||||||
|
const issImage = "../Seasonals/Resources/space_assets/iss.png";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://lottiefiles.com/free-animation/rocket-MYUQ3UFq3k
|
||||||
|
* https://pixabay.com/de/vectors/space-shuttle-atlantis-nasa-156012/
|
||||||
|
*/
|
||||||
|
const rocketImages = [
|
||||||
|
"../Seasonals/Resources/space_assets/rocket.gif",
|
||||||
|
"../Seasonals/Resources/space_assets/space-shuttle.png"
|
||||||
|
]
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -48,71 +88,192 @@ function createSpace() {
|
|||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
const standardCount = 15;
|
// const standardPlanetCount = 4;
|
||||||
const totalSymbols = symbolCount + standardCount;
|
// const standardAstronautCount = 1;
|
||||||
|
// const standardSatelliteCount = 2;
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
// const standardIssCount = 1;
|
||||||
let finalCount = totalSymbols;
|
// const standardRocketCount = 1;
|
||||||
|
|
||||||
if (isMobile) {
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
finalCount = enableRandomMobile ? totalSymbols : standardCount;
|
let divisor = isMobile ? Math.max(1, symbolCountMobile) : 1;
|
||||||
|
let pCount = Math.floor(planetCountConf / divisor);
|
||||||
|
let aCount = Math.floor(astronautCountConf / divisor);
|
||||||
|
let sCount = Math.floor(satelliteCountConf / divisor);
|
||||||
|
let iCount = Math.floor(issCountConf / divisor);
|
||||||
|
let rCount = Math.floor(rocketCountConf / divisor);
|
||||||
|
|
||||||
|
// Add Nebula Glow
|
||||||
|
const bgGlow = document.createElement('div');
|
||||||
|
bgGlow.className = 'space-bg-glow';
|
||||||
|
container.appendChild(bgGlow);
|
||||||
|
|
||||||
|
// Add CSS Starfield
|
||||||
|
const starfield = document.createElement('div');
|
||||||
|
starfield.className = 'space-starfield';
|
||||||
|
let boxShadows1 = [];
|
||||||
|
let boxShadows2 = [];
|
||||||
|
let boxShadows3 = [];
|
||||||
|
|
||||||
|
// Generate random stars for parallax starfield using CSS % / vw sizes for responsiveness
|
||||||
|
for (let i = 0; i < 150; i++) {
|
||||||
|
let x = (Math.random() * 100).toFixed(2);
|
||||||
|
let y = (Math.random() * 100).toFixed(2);
|
||||||
|
boxShadows1.push(`${x}vw ${y}vh #FFF`);
|
||||||
|
boxShadows1.push(`${x}vw ${(parseFloat(y) + 100).toFixed(2)}vh #FFF`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
let x = (Math.random() * 100).toFixed(2);
|
||||||
|
let y = (Math.random() * 100).toFixed(2);
|
||||||
|
boxShadows2.push(`${x}vw ${y}vh #FFF`);
|
||||||
|
boxShadows2.push(`${x}vw ${(parseFloat(y) + 100).toFixed(2)}vh #FFF`);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
let x = (Math.random() * 100).toFixed(2);
|
||||||
|
let y = (Math.random() * 100).toFixed(2);
|
||||||
|
boxShadows3.push(`${x}vw ${y}vh #FFF`);
|
||||||
|
boxShadows3.push(`${x}vw ${(parseFloat(y) + 100).toFixed(2)}vh #FFF`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const starLayer1 = document.createElement('div');
|
||||||
|
starLayer1.style.width = '1px'; starLayer1.style.height = '1px';
|
||||||
|
starLayer1.style.background = 'transparent';
|
||||||
|
starLayer1.style.boxShadow = boxShadows1.join(", ");
|
||||||
|
starLayer1.style.animation = 'space-star-drift 200s linear infinite';
|
||||||
|
starfield.appendChild(starLayer1);
|
||||||
|
|
||||||
|
const starLayer2 = document.createElement('div');
|
||||||
|
starLayer2.style.width = '2px'; starLayer2.style.height = '2px';
|
||||||
|
starLayer2.style.background = 'transparent';
|
||||||
|
starLayer2.style.boxShadow = boxShadows2.join(", ");
|
||||||
|
starLayer2.style.animation = 'space-star-drift 150s linear infinite';
|
||||||
|
starfield.appendChild(starLayer2);
|
||||||
|
|
||||||
|
const starLayer3 = document.createElement('div');
|
||||||
|
starLayer3.style.width = '3px'; starLayer3.style.height = '3px';
|
||||||
|
starLayer3.style.background = 'transparent';
|
||||||
|
starLayer3.style.boxShadow = boxShadows3.join(", ");
|
||||||
|
starLayer3.style.animation = 'space-star-drift 100s linear infinite';
|
||||||
|
starfield.appendChild(starLayer3);
|
||||||
|
|
||||||
|
container.appendChild(starfield);
|
||||||
|
|
||||||
|
// Shooting stars
|
||||||
|
const shootingStarCount = isMobile ? 1 : 2; // Less frequent
|
||||||
|
for (let i = 0; i < shootingStarCount; i++) {
|
||||||
|
const streak = document.createElement('div');
|
||||||
|
streak.className = 'space-shooting-star';
|
||||||
|
// Pick a random tail direction and fall direction to match
|
||||||
|
const isFromLeft = Math.random() > 0.5;
|
||||||
|
// Direction angle: random between 15deg-75deg (left) or 105deg-165deg (right)
|
||||||
|
// so they don't always fall in the exact same quadrant trajectory
|
||||||
|
let angle = isFromLeft
|
||||||
|
? Math.random() * 60 + 15
|
||||||
|
: Math.random() * 60 + 105;
|
||||||
|
|
||||||
|
streak.style.setProperty('--shoot-angle', `${angle}deg`);
|
||||||
|
|
||||||
|
const topStart = Math.random() * 50;
|
||||||
|
streak.style.left = isFromLeft ? '-20vw' : '120vw';
|
||||||
|
streak.style.top = `${topStart}vh`;
|
||||||
|
|
||||||
|
// Travel 200 viewport widths exactly along the rotated angle
|
||||||
|
streak.style.setProperty('--shoot-distance', '200vw');
|
||||||
|
|
||||||
|
streak.style.animationDelay = `${Math.random() * 20}s`;
|
||||||
|
|
||||||
|
// MARK: Shooting Star Speed
|
||||||
|
const flightCycleDuration = Math.random() * 10 + 15; // 15-25s
|
||||||
|
streak.style.animationDuration = `${flightCycleDuration}s`;
|
||||||
|
|
||||||
|
container.appendChild(streak);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRandomDuration = enableDifferentDuration !== false;
|
const useRandomDuration = enableDifferentDuration !== false;
|
||||||
|
|
||||||
const activeItems = ['planet1', 'planet2', 'star', 'astronaut', 'rocket'];
|
function createSpaceItem(imageArr, cCount, addedClass) {
|
||||||
|
for (let i = 0; i < cCount; i++) {
|
||||||
|
let symbol = document.createElement('div');
|
||||||
|
|
||||||
|
const randomImage = imageArr[Math.floor(Math.random() * imageArr.length)];
|
||||||
|
symbol.className = `space-symbol ${addedClass}`;
|
||||||
|
|
||||||
for (let i = 0; i < finalCount; i++) {
|
let img = document.createElement('img');
|
||||||
let symbol = document.createElement('div');
|
img.src = randomImage;
|
||||||
|
img.onerror = function() {
|
||||||
const randomItem = activeItems[Math.floor(Math.random() * activeItems.length)];
|
this.style.display = 'none';
|
||||||
symbol.className = `space-symbol space-${randomItem}`;
|
};
|
||||||
|
symbol.appendChild(img);
|
||||||
|
|
||||||
let img = document.createElement('img');
|
const topPos = Math.random() * 90; // 0 to 90vh
|
||||||
img.src = `../Seasonals/Resources/space_images/${randomItem}.png`;
|
|
||||||
img.onerror = function() {
|
// Zero gravity sizes / speeds
|
||||||
this.style.display = 'none';
|
const depth = Math.random();
|
||||||
this.parentElement.innerHTML = getSpaceEmojiFallback(randomItem);
|
// Make background elements (depth close to 0) much smaller than foreground
|
||||||
};
|
const distanceScale = 0.15 + (depth * 0.85); // 0.15 to 1.0
|
||||||
symbol.appendChild(img);
|
|
||||||
|
symbol.style.zIndex = Math.floor(depth * 30) + 20;
|
||||||
|
|
||||||
const topPos = Math.random() * 90; // 0 to 90vh
|
let durationSeconds = 30; // Very slow
|
||||||
const delaySeconds = Math.random() * 10;
|
if (useRandomDuration) {
|
||||||
|
durationSeconds = (1 - depth) * 40 + 30 + Math.random() * 10 - 5;
|
||||||
let durationSeconds = 15;
|
}
|
||||||
if (useRandomDuration) {
|
|
||||||
durationSeconds = Math.random() * 15 + 15; // 15 to 30 seconds for slow drift
|
// Randomly pick direction: left-to-right OR right-to-left
|
||||||
|
const goRight = Math.random() > 0.5;
|
||||||
|
const baseTransformScale = goRight ? 'scaleX(-1)' : 'scaleX(1)';
|
||||||
|
|
||||||
|
if (goRight) {
|
||||||
|
symbol.style.animationName = 'space-drift-right';
|
||||||
|
symbol.style.left = '-20vw';
|
||||||
|
symbol.style.right = 'auto';
|
||||||
|
} else {
|
||||||
|
symbol.style.animationName = 'space-drift-left';
|
||||||
|
symbol.style.right = '-20vw';
|
||||||
|
symbol.style.left = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol.style.top = `${topPos}vh`;
|
||||||
|
symbol.style.animationDuration = `${durationSeconds}s`;
|
||||||
|
|
||||||
|
// Negative delay correctly scatters them initially across the screen
|
||||||
|
// so they don't all appear to spawn from the edge at the start
|
||||||
|
const delaySeconds = -(Math.random() * durationSeconds);
|
||||||
|
symbol.style.animationDelay = `${delaySeconds}s`;
|
||||||
|
|
||||||
|
// Slow rotation inside inner div
|
||||||
|
const rotationDiv = document.createElement('div');
|
||||||
|
const rotDur = Math.random() * 20 + 20; // 20-40s spin
|
||||||
|
const spinReverse = Math.random() > 0.5 ? 'reverse' : 'normal';
|
||||||
|
rotationDiv.style.animation = `space-slow-spin ${rotDur}s linear infinite ${spinReverse}`;
|
||||||
|
|
||||||
|
// Apply final static scaling and facing to inner image directly
|
||||||
|
img.style.transform = `scale(${distanceScale}) ${baseTransformScale}`;
|
||||||
|
|
||||||
|
rotationDiv.appendChild(img);
|
||||||
|
symbol.appendChild(rotationDiv);
|
||||||
|
|
||||||
|
// Swap to a random image from the pool every time it completes an orbit (disappears)
|
||||||
|
if (imageArr.length > 1) {
|
||||||
|
// The animation delay pushes the initial cycle, so we use setInterval matched to duration
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
if (!document.body.contains(container)) { clearInterval(intervalId); return; }
|
||||||
|
// Update only if currently out of bounds to avoid popping
|
||||||
|
const rect = symbol.getBoundingClientRect();
|
||||||
|
if (rect.right < 0 || rect.left > window.innerWidth) {
|
||||||
|
img.src = imageArr[Math.floor(Math.random() * imageArr.length)];
|
||||||
|
}
|
||||||
|
}, 2000); // Check occasionally if it's off screen
|
||||||
|
}
|
||||||
|
|
||||||
|
container.appendChild(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Randomly pick direction: left-to-right OR right-to-left
|
|
||||||
const goRight = Math.random() > 0.5;
|
|
||||||
if (goRight) {
|
|
||||||
symbol.style.animationName = 'space-drift-right';
|
|
||||||
symbol.style.left = '-10vw';
|
|
||||||
symbol.style.transform = 'scaleX(-1)'; // flip some items horizontally if moving right
|
|
||||||
} else {
|
|
||||||
symbol.style.animationName = 'space-drift-left';
|
|
||||||
symbol.style.right = '-10vw';
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol.style.top = `${topPos}vh`;
|
|
||||||
symbol.style.animationDuration = `${durationSeconds}s`;
|
|
||||||
symbol.style.animationDelay = `${delaySeconds}s`;
|
|
||||||
|
|
||||||
// Add a slow rotation
|
|
||||||
symbol.style.setProperty('--rot-dur', `${durationSeconds}s`);
|
|
||||||
|
|
||||||
container.appendChild(symbol);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function getSpaceEmojiFallback(type) {
|
createSpaceItem(planetImages, pCount, 'space-planet');
|
||||||
if (type === 'planet1') return '🪐';
|
createSpaceItem(astronautImages, aCount, 'space-astronaut');
|
||||||
if (type === 'planet2') return '🌍';
|
createSpaceItem(satelliteImages, sCount, 'space-satellite');
|
||||||
if (type === 'star') return '⭐';
|
createSpaceItem([issImage], iCount, 'space-iss');
|
||||||
if (type === 'astronaut') return '👨🚀';
|
createSpaceItem(rocketImages, rCount, 'space-rocket');
|
||||||
if (type === 'rocket') return '🚀';
|
|
||||||
return '✨';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeSpace() {
|
function initializeSpace() {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
contain: layout paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spooky {
|
.spooky {
|
||||||
@@ -16,19 +17,8 @@
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
translate: 0 120vh;
|
translate: 0 120vh;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
-webkit-animation-name: spooky-float;
|
|
||||||
-webkit-animation-duration: 10s;
|
|
||||||
-webkit-animation-timing-function: linear;
|
|
||||||
-webkit-animation-iteration-count: infinite;
|
|
||||||
-webkit-animation-play-state: running;
|
|
||||||
|
|
||||||
animation-name: spooky-float;
|
animation-name: spooky-float;
|
||||||
animation-duration: 10s;
|
animation-duration: 10s;
|
||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
@@ -40,13 +30,6 @@
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
height: auto;
|
height: auto;
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
|
|
||||||
-webkit-animation-name: spooky-shake;
|
|
||||||
-webkit-animation-duration: 3s;
|
|
||||||
-webkit-animation-timing-function: ease-in-out;
|
|
||||||
-webkit-animation-iteration-count: infinite;
|
|
||||||
-webkit-animation-play-state: running;
|
|
||||||
|
|
||||||
animation-name: spooky-shake;
|
animation-name: spooky-shake;
|
||||||
animation-duration: 3s;
|
animation-duration: 3s;
|
||||||
animation-timing-function: ease-in-out;
|
animation-timing-function: ease-in-out;
|
||||||
@@ -59,22 +42,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes spooky-float {
|
|
||||||
0% {
|
|
||||||
translate: 0 120vh;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
translate: 0 -150px;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spooky-float {
|
@keyframes spooky-float {
|
||||||
0% {
|
0% {
|
||||||
@@ -93,14 +60,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes spooky-shake {
|
|
||||||
0%, 100% {
|
|
||||||
transform: translateX(0) scale(1) rotate(15deg);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: translateX(80px) scale(1.2) rotate(-15deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spooky-shake {
|
@keyframes spooky-shake {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
@@ -111,7 +70,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Base predefined starting offsets (if not overridden by js) */
|
|
||||||
.spooky:nth-of-type(0) { left: 1%; }
|
.spooky:nth-of-type(0) { left: 1%; }
|
||||||
.spooky:nth-of-type(1) { left: 10%; }
|
.spooky:nth-of-type(1) { left: 10%; }
|
||||||
.spooky:nth-of-type(2) { left: 20%; }
|
.spooky:nth-of-type(2) { left: 20%; }
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Spooky || {};
|
const config = window.SeasonalsPluginConfig?.Spooky || {};
|
||||||
|
|
||||||
const spooky = config.EnableSpooky !== undefined ? config.EnableSpooky : true; // enable/disable
|
const spooky = config.EnableSpooky !== undefined ? config.EnableSpooky : true; // enable/disable spooky
|
||||||
const spookyCount = config.SymbolCount || 25; // count of random extra symbols
|
const spookyCount = config.SymbolCount !== undefined ? config.SymbolCount : 25; // count of symbols
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableSpookySway = config.EnableSpookySway !== undefined ? config.EnableSpookySway : true;
|
const enableSpookySway = config.EnableSpookySway !== undefined ? config.EnableSpookySway : true; // enable/disable spooky sway
|
||||||
const spookySize = config.SpookySize || 20;
|
const spookySize = config.SpookySize !== undefined ? config.SpookySize : 20; // size of elements
|
||||||
const spookyGlowSize = config.SpookyGlowSize !== undefined ? config.SpookyGlowSize : 2;
|
const spookyGlowSize = config.SpookyGlowSize !== undefined ? config.SpookyGlowSize : 2; // size of element glow
|
||||||
|
|
||||||
|
const spookyImages = [
|
||||||
|
"../Seasonals/Resources/halloween_images/ghost_20x20.png",
|
||||||
|
"../Seasonals/Resources/halloween_images/bat_20x20.png",
|
||||||
|
"../Seasonals/Resources/halloween_images/pumpkin_20x20.png",
|
||||||
|
];
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -20,13 +26,13 @@ function toggleSpooky() {
|
|||||||
const hasUserMenu = document.querySelector('#app-user-menu');
|
const hasUserMenu = document.querySelector('#app-user-menu');
|
||||||
|
|
||||||
if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) {
|
if (videoPlayer || trailerPlayer || isDashboard || hasUserMenu) {
|
||||||
spookyContainer.style.display = 'none'; // hide spooky
|
spookyContainer.style.display = 'none';
|
||||||
if (!msgPrinted) {
|
if (!msgPrinted) {
|
||||||
console.log('Spooky Theme hidden');
|
console.log('Spooky Theme hidden');
|
||||||
msgPrinted = true;
|
msgPrinted = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spookyContainer.style.display = 'block'; // show spooky
|
spookyContainer.style.display = 'block';
|
||||||
if (msgPrinted) {
|
if (msgPrinted) {
|
||||||
console.log('Spooky Theme visible');
|
console.log('Spooky Theme visible');
|
||||||
msgPrinted = false;
|
msgPrinted = false;
|
||||||
@@ -34,7 +40,6 @@ function toggleSpooky() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// observe changes in the DOM
|
|
||||||
const observer = new MutationObserver(toggleSpooky);
|
const observer = new MutationObserver(toggleSpooky);
|
||||||
observer.observe(document.body, {
|
observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
@@ -42,13 +47,7 @@ observer.observe(document.body, {
|
|||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const spookyImages = [
|
|
||||||
"../Seasonals/Resources/halloween_images/ghost_20x20.png",
|
|
||||||
"../Seasonals/Resources/halloween_images/bat_20x20.png",
|
|
||||||
"../Seasonals/Resources/halloween_images/pumpkin_20x20.png",
|
|
||||||
];
|
|
||||||
|
|
||||||
// create spooky objects
|
|
||||||
function createSpooky() {
|
function createSpooky() {
|
||||||
const container = document.querySelector('.spooky-container') || document.createElement("div");
|
const container = document.querySelector('.spooky-container') || document.createElement("div");
|
||||||
|
|
||||||
@@ -95,7 +94,6 @@ function createSpooky() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add configured extra symbols
|
|
||||||
for (let i = 0; i < spookyCount; i++) {
|
for (let i = 0; i < spookyCount; i++) {
|
||||||
const spookyOuter = document.createElement("div");
|
const spookyOuter = document.createElement("div");
|
||||||
spookyOuter.className = "spooky";
|
spookyOuter.className = "spooky";
|
||||||
|
|||||||
@@ -5,17 +5,21 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 9999;
|
z-index: 10;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sports-symbol {
|
.sports-symbol {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10vh;
|
top: 0;
|
||||||
animation: sports-fall linear infinite;
|
|
||||||
font-size: 3rem; /* Fallback emoji size */
|
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
|
z-index: 40;
|
||||||
|
translate: 0 -10vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sports-inner {
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sports-symbol img {
|
.sports-symbol img {
|
||||||
@@ -26,13 +30,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sports-confetti {
|
.sports-confetti {
|
||||||
|
will-change: transform, opacity;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -5vh;
|
top: 0;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
animation: sports-confetti-fall linear infinite;
|
animation: sports-confetti-fall linear infinite;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
translate: 0 -5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sports-confetti.circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sports-confetti.triangle {
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-bottom: 10px solid var(--shape-color, #FFCC00);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sports-turf {
|
.sports-turf {
|
||||||
@@ -46,26 +65,60 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sports-fall {
|
@keyframes sports-bounce {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(-10vh) rotate(var(--start-rot, 0deg));
|
transform: translateY(-10vh);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
animation-timing-function: ease-in;
|
||||||
}
|
}
|
||||||
10% {
|
5% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
85% {
|
30% {
|
||||||
|
transform: translateY(85vh);
|
||||||
|
animation-timing-function: ease-out;
|
||||||
|
} /* hit ground, start bouncing up */
|
||||||
|
50% {
|
||||||
|
transform: translateY(40vh);
|
||||||
|
animation-timing-function: ease-in;
|
||||||
|
} /* peak of bounce, start falling */
|
||||||
|
70% {
|
||||||
|
transform: translateY(85vh);
|
||||||
|
animation-timing-function: ease-out;
|
||||||
|
} /* hit ground, bounce up */
|
||||||
|
85% {
|
||||||
|
transform: translateY(70vh);
|
||||||
|
animation-timing-function: ease-in;
|
||||||
|
} /* smaller peak */
|
||||||
|
95% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(110vh) rotate(var(--end-rot, 360deg));
|
transform: translateY(110vh);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes sports-fall {
|
||||||
|
0% { transform: translateY(-10vh); opacity: 0; }
|
||||||
|
5% { opacity: 1; }
|
||||||
|
90% { opacity: 1; }
|
||||||
|
100% { transform: translateY(110vh); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sports-sway {
|
||||||
|
0% { transform: rotate(-15deg) translateX(-10px); }
|
||||||
|
100% { transform: rotate(15deg) translateX(10px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sports-spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(var(--spin-rot, 360deg)); }
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes sports-confetti-fall {
|
@keyframes sports-confetti-fall {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(-5vh) rotateX(0deg) rotateY(0deg);
|
transform: translateY(-5vh) rotate3d(var(--rx), var(--ry), var(--rz), 0deg);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
5% {
|
5% {
|
||||||
@@ -75,7 +128,25 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(105vh) rotateX(720deg) rotateY(360deg);
|
transform: translateY(105vh) rotate3d(var(--rx), var(--ry), var(--rz), var(--rot-dir));
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes sports-arc-x-right {
|
||||||
|
0% { transform: translateX(0); }
|
||||||
|
100% { transform: translateX(130vw); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sports-arc-x-left {
|
||||||
|
0% { transform: translateX(0); }
|
||||||
|
100% { transform: translateX(-130vw); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sports-arc-y {
|
||||||
|
0% { transform: translateY(110vh) scale(0.5) rotate(-30deg); opacity: 0; animation-timing-function: ease-out; }
|
||||||
|
5% { opacity: 1; }
|
||||||
|
50% { transform: translateY(10vh) scale(1.5) rotate(0deg); animation-timing-function: ease-in; }
|
||||||
|
95% { opacity: 1; }
|
||||||
|
100% { transform: translateY(110vh) scale(0.5) rotate(30deg); opacity: 0; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,30 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Sports || {};
|
const config = window.SeasonalsPluginConfig?.Sports || {};
|
||||||
|
|
||||||
const sports = config.EnableSports !== undefined ? config.EnableSports : true;
|
const sports = config.EnableSports !== undefined ? config.EnableSports : true; // enable/disable sports
|
||||||
const symbolCount = config.SymbolCount || 25;
|
const symbolCount = config.SymbolCount !== undefined ? config.SymbolCount : 5; // count of balls per category
|
||||||
const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const enableTrophy = config.EnableTrophy !== undefined ? config.EnableTrophy : false; // enable/disable trophy
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const rawSportsBalls = config.SportsBalls !== undefined ? config.SportsBalls : 'football,basketball,tennis,volleyball'; // set sports categories to spawn
|
||||||
|
const turfColorHex = config.TurfColor !== undefined ? config.TurfColor : '#228b22'; // color of turf
|
||||||
|
const confettiColors = config.ConfettiColors ? config.ConfettiColors.split(',') : ['#000000', '#FF0000', '#FFCC00']; // Add Country Colored confetti
|
||||||
|
|
||||||
|
// Pre-declare and manage image assets
|
||||||
|
// Credits: https://flaticon.com
|
||||||
|
const SPORTS_ASSETS = {
|
||||||
|
badminton: ['badminton_1', 'badminton_2'],
|
||||||
|
baseball: ['baseball_1', 'baseball_2'],
|
||||||
|
basketball: ['basketball_1', 'basketball_2'],
|
||||||
|
billiard: Array.from({length: 14}, (_, i) => `billiard_ball_${i + 1}`),
|
||||||
|
bowling: ['bowling_1', 'bowling_2'],
|
||||||
|
football: Array.from({length: 5}, (_, i) => `football_${i + 1}`),
|
||||||
|
golf: ['golf_ball_1', 'golf_ball_2'],
|
||||||
|
rugby: ['rugby_ball_1', 'rugby_ball_2'],
|
||||||
|
table_tennis: ['table_tennis_ball_1', 'table_tennis_ball_2'],
|
||||||
|
tennis: ['tennis_ball_1', 'tennis_ball_2'],
|
||||||
|
volleyball: ['volleyball_1', 'volleyball_2'],
|
||||||
|
waterball: ['waterball_1', 'waterball_2']
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -48,44 +68,52 @@ function createSports() {
|
|||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a turf/grass overlay at the bottom
|
// Create a turf/grass overlay at the bottom using the provided hex
|
||||||
const turf = document.createElement('div');
|
const turf = document.createElement('div');
|
||||||
turf.className = 'sports-turf';
|
turf.className = 'sports-turf';
|
||||||
|
// Using hex with transparency
|
||||||
|
turf.style.background = `linear-gradient(180deg, transparent 0%, ${turfColorHex}4D 30%, ${turfColorHex}CC 100%)`;
|
||||||
container.appendChild(turf);
|
container.appendChild(turf);
|
||||||
|
|
||||||
const standardCount = 15;
|
|
||||||
const totalSymbols = symbolCount + standardCount;
|
|
||||||
|
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
let finalCount = totalSymbols;
|
let ballsPerCategory = symbolCount;
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile && !enableRandomMobile) {
|
||||||
finalCount = enableRandomMobile ? totalSymbols : standardCount;
|
ballsPerCategory = Math.min(symbolCount, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRandomDuration = enableDifferentDuration !== false;
|
const useRandomDuration = enableDifferentDuration !== false;
|
||||||
|
|
||||||
// Standard sports items to spawn
|
// Map standard sports balls to spawn based on category configuration
|
||||||
const activeItems = ['soccer', 'football', 'yellow_card', 'red_card', 'trophy'];
|
const chosenCategories = rawSportsBalls.split(',').map(s => s.trim()).filter(s => s !== '');
|
||||||
|
|
||||||
// Create falling sports items
|
const createBall = (randomItem) => {
|
||||||
for (let i = 0; i < finalCount; i++) {
|
|
||||||
let symbol = document.createElement('div');
|
let symbol = document.createElement('div');
|
||||||
|
|
||||||
// Randomly pick an item
|
|
||||||
const randomItem = activeItems[Math.floor(Math.random() * activeItems.length)];
|
|
||||||
symbol.className = `sports-symbol sports-${randomItem}`;
|
symbol.className = `sports-symbol sports-${randomItem}`;
|
||||||
|
|
||||||
|
// Create inner div for spinning rotation
|
||||||
|
let innerDiv = document.createElement('div');
|
||||||
|
innerDiv.className = 'sports-inner';
|
||||||
|
|
||||||
// Try load image
|
// Try load image
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = `../Seasonals/Resources/sports_images/${randomItem}.png`;
|
img.src = `../Seasonals/Resources/sport_assets/${randomItem}.png`;
|
||||||
img.onerror = function() {
|
img.onerror = function() {
|
||||||
this.style.display = 'none'; // hide broken image icon
|
symbol.remove();
|
||||||
this.parentElement.innerHTML = getEmojiFallback(randomItem); // inject emoji fallback
|
|
||||||
};
|
};
|
||||||
symbol.appendChild(img);
|
innerDiv.appendChild(img);
|
||||||
|
|
||||||
|
// Balls should bounce infinitely
|
||||||
|
symbol.style.animationName = 'sports-bounce';
|
||||||
|
symbol.style.animationIterationCount = 'infinite';
|
||||||
|
innerDiv.style.animationName = 'sports-spin';
|
||||||
|
innerDiv.style.animationIterationCount = 'infinite';
|
||||||
|
innerDiv.style.animationTimingFunction = 'linear';
|
||||||
|
|
||||||
|
symbol.appendChild(innerDiv);
|
||||||
|
|
||||||
const leftPos = Math.random() * 100;
|
const leftPos = Math.random() * 95;
|
||||||
const delaySeconds = Math.random() * 10;
|
const delaySeconds = Math.random() * 10;
|
||||||
|
|
||||||
let durationSeconds = 8;
|
let durationSeconds = 8;
|
||||||
@@ -93,20 +121,94 @@ function createSports() {
|
|||||||
durationSeconds = Math.random() * 4 + 6; // 6 to 10 seconds
|
durationSeconds = Math.random() * 4 + 6; // 6 to 10 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a random slight rotation difference
|
// Add a random spin
|
||||||
const startRot = Math.random() * 360;
|
const spinRot = (Math.random() > 0.5 ? 360 : -360) + "deg";
|
||||||
symbol.style.setProperty('--start-rot', `${startRot}deg`);
|
innerDiv.style.setProperty('--spin-rot', spinRot);
|
||||||
symbol.style.setProperty('--end-rot', `${startRot + (Math.random() > 0.5 ? 360 : -360)}deg`);
|
|
||||||
|
// Duration for the spin should be different from fall to look natural
|
||||||
|
const spinDuration = Math.random() * 2 + 2;
|
||||||
|
innerDiv.style.animationDuration = `${spinDuration}s`;
|
||||||
|
|
||||||
symbol.style.left = `${leftPos}vw`;
|
symbol.style.left = `${leftPos}vw`;
|
||||||
symbol.style.animationDuration = `${durationSeconds}s`;
|
symbol.style.animationDuration = `${durationSeconds}s`;
|
||||||
symbol.style.animationDelay = `${delaySeconds}s`;
|
symbol.style.animationDelay = `${delaySeconds}s`;
|
||||||
|
|
||||||
container.appendChild(symbol);
|
container.appendChild(symbol);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create falling sports balls
|
||||||
|
chosenCategories.forEach(category => {
|
||||||
|
let variants = SPORTS_ASSETS[category];
|
||||||
|
if (!variants) variants = [category];
|
||||||
|
|
||||||
|
for (let i = 0; i < ballsPerCategory; i++) {
|
||||||
|
// Pick a random variant
|
||||||
|
const randomItem = variants[Math.floor(Math.random() * variants.length)];
|
||||||
|
createBall(randomItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the periodic flying trophy arc
|
||||||
|
function launchTrophy() {
|
||||||
|
if (!document.querySelector('.sports-container')) return;
|
||||||
|
|
||||||
|
const flyFromLeft = Math.random() > 0.5;
|
||||||
|
let trophySymbol = document.createElement('div');
|
||||||
|
trophySymbol.className = "sports-symbol sports-trophy-wrapper";
|
||||||
|
|
||||||
|
let trophyInner = document.createElement('div');
|
||||||
|
trophyInner.className = "sports-inner sports-trophy-inner";
|
||||||
|
|
||||||
|
let trophyImg = document.createElement('img');
|
||||||
|
trophyImg.src = `../Seasonals/Resources/sport_assets/trophy.gif`;
|
||||||
|
trophyImg.style.transform = `scale(${Math.random() * 0.5 + 0.8})`;
|
||||||
|
trophyImg.onerror = function() {
|
||||||
|
this.style.display = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
trophyInner.appendChild(trophyImg);
|
||||||
|
trophySymbol.appendChild(trophyInner);
|
||||||
|
|
||||||
|
if (flyFromLeft) {
|
||||||
|
trophySymbol.style.animationName = "sports-arc-x-right";
|
||||||
|
trophySymbol.style.left = "-15vw";
|
||||||
|
} else {
|
||||||
|
trophySymbol.style.animationName = "sports-arc-x-left";
|
||||||
|
trophySymbol.style.left = "115vw";
|
||||||
|
}
|
||||||
|
|
||||||
|
trophyInner.style.animationName = "sports-arc-y";
|
||||||
|
|
||||||
|
// Appearance timing
|
||||||
|
const arcDuration = 6 + Math.random() * 2;
|
||||||
|
|
||||||
|
trophySymbol.style.animationDuration = `${arcDuration}s`;
|
||||||
|
trophyInner.style.animationDuration = `${arcDuration}s`;
|
||||||
|
|
||||||
|
// Prevent looping for the trophy
|
||||||
|
trophySymbol.style.animationIterationCount = "1";
|
||||||
|
trophyInner.style.animationIterationCount = "1";
|
||||||
|
trophySymbol.style.animationFillMode = "forwards";
|
||||||
|
trophyInner.style.animationFillMode = "forwards";
|
||||||
|
|
||||||
|
container.appendChild(trophySymbol);
|
||||||
|
|
||||||
|
// Remove node after animation completes
|
||||||
|
setTimeout(() => {
|
||||||
|
if (trophySymbol && trophySymbol.parentNode) {
|
||||||
|
trophySymbol.parentNode.removeChild(trophySymbol);
|
||||||
|
}
|
||||||
|
}, arcDuration * 1000 + 500);
|
||||||
|
|
||||||
|
// Schedule the next trophy
|
||||||
|
setTimeout(() => { if (document.body.contains(container)) launchTrophy(); }, Math.random() * 20000 + 10000); // Wait 10-30s until next trophy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch initial trophy after a short delay
|
||||||
|
if (enableTrophy) {
|
||||||
|
setTimeout(() => { if (document.body.contains(container)) launchTrophy(); }, Math.random() * 5000 + 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Germany Colored confetti (Black, Red, Gold)
|
|
||||||
const confettiColors = ['#000000', '#FF0000', '#FFCC00'];
|
|
||||||
const confettiCount = isMobile ? 30 : 60;
|
const confettiCount = isMobile ? 30 : 60;
|
||||||
|
|
||||||
for (let i = 0; i < confettiCount; i++) {
|
for (let i = 0; i < confettiCount; i++) {
|
||||||
@@ -116,6 +218,23 @@ function createSports() {
|
|||||||
const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
|
const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
|
||||||
confetti.style.backgroundColor = color;
|
confetti.style.backgroundColor = color;
|
||||||
|
|
||||||
|
// Random shape generator for varied confetti
|
||||||
|
const shape = Math.random();
|
||||||
|
if (shape > 0.66) {
|
||||||
|
confetti.classList.add('circle');
|
||||||
|
const size = Math.random() * 5 + 5; // 5-10px
|
||||||
|
confetti.style.width = `${size}px`;
|
||||||
|
confetti.style.height = `${size}px`;
|
||||||
|
} else if (shape > 0.33) {
|
||||||
|
confetti.classList.add('rect');
|
||||||
|
const width = Math.random() * 4 + 4; // 4-8px
|
||||||
|
const height = Math.random() * 5 + 8; // 8-13px
|
||||||
|
confetti.style.width = `${width}px`;
|
||||||
|
confetti.style.height = `${height}px`;
|
||||||
|
} else {
|
||||||
|
confetti.classList.add('triangle');
|
||||||
|
}
|
||||||
|
|
||||||
const leftPos = Math.random() * 100;
|
const leftPos = Math.random() * 100;
|
||||||
const delaySeconds = Math.random() * 8;
|
const delaySeconds = Math.random() * 8;
|
||||||
const duration = Math.random() * 3 + 4; // 4 to 7 seconds
|
const duration = Math.random() * 3 + 4; // 4 to 7 seconds
|
||||||
@@ -123,20 +242,17 @@ function createSports() {
|
|||||||
confetti.style.left = `${leftPos}vw`;
|
confetti.style.left = `${leftPos}vw`;
|
||||||
confetti.style.animationDuration = `${duration}s`;
|
confetti.style.animationDuration = `${duration}s`;
|
||||||
confetti.style.animationDelay = `${delaySeconds}s`;
|
confetti.style.animationDelay = `${delaySeconds}s`;
|
||||||
|
|
||||||
|
// Random 3D Rotation for flutter
|
||||||
|
confetti.style.setProperty('--rx', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--ry', Math.random().toFixed(2));
|
||||||
|
confetti.style.setProperty('--rz', (Math.random() * 0.5).toFixed(2));
|
||||||
|
confetti.style.setProperty('--rot-dir', `${(Math.random() > 0.5 ? 1 : -1) * 360}deg`);
|
||||||
|
|
||||||
container.appendChild(confetti);
|
container.appendChild(confetti);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEmojiFallback(type) {
|
|
||||||
if (type === 'soccer') return '⚽';
|
|
||||||
if (type === 'football') return '🏈';
|
|
||||||
if (type === 'yellow_card') return '🟨';
|
|
||||||
if (type === 'red_card') return '🟥';
|
|
||||||
if (type === 'trophy') return '🏆';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeSports() {
|
function initializeSports() {
|
||||||
if (!sports) return;
|
if (!sports) return;
|
||||||
createSports();
|
createSports();
|
||||||
|
|||||||
@@ -29,13 +29,14 @@
|
|||||||
/* Sunbeams */
|
/* Sunbeams */
|
||||||
.spring-sunbeam {
|
.spring-sunbeam {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: -50%;
|
top: 0;
|
||||||
height: 200%;
|
height: 200%;
|
||||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 200, 0.08) 50%, rgba(255, 255, 255, 0));
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 200, 0.08) 50%, rgba(255, 255, 255, 0));
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
transform-origin: top center;
|
transform-origin: top center;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
translate: 0 -50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grass Container (Wrapper) */
|
/* Grass Container (Wrapper) */
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
|
|
||||||
/* SVG Meadow Layer */
|
/* SVG Meadow Layer */
|
||||||
.spring-meadow-layer {
|
.spring-meadow-layer {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -94,6 +96,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spring-sway {
|
.spring-sway {
|
||||||
|
will-change: transform;
|
||||||
transform-origin: bottom center;
|
transform-origin: bottom center;
|
||||||
animation: spring-meadow-sway 4s ease-in-out infinite alternate;
|
animation: spring-meadow-sway 4s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Spring || {};
|
const config = window.SeasonalsPluginConfig?.Spring || {};
|
||||||
|
|
||||||
const spring = config.EnableSpring !== undefined ? config.EnableSpring : true; // Enable/disable spring
|
const spring = config.EnableSpring !== undefined ? config.EnableSpring : true; // enable/disable spring
|
||||||
const pollenCount = config.PollenCount || 30; // Number of pollen particles
|
const pollenCount = config.PollenCount !== undefined ? config.PollenCount : 30; // count of pollen
|
||||||
const sunbeamCount = config.SunbeamCount || 5; // Number of sunbeams
|
const enableSunbeams = config.EnableSpringSunbeams !== undefined ? config.EnableSpringSunbeams : true; // enable/disable sunbeams
|
||||||
const enableSunbeams = config.EnableSpringSunbeams !== undefined ? config.EnableSpringSunbeams : true; // Enable/disable sunbeams
|
const sunbeamCount = config.SunbeamCount !== undefined ? config.SunbeamCount : 5; // count of sunbeams
|
||||||
const birdCount = config.BirdCount !== undefined ? config.BirdCount : 3; // Number of birds
|
const birdCount = config.BirdCount !== undefined ? config.BirdCount : 3; // count of birds
|
||||||
const butterflyCount = config.ButterflyCount !== undefined ? config.ButterflyCount : 4; // Number of butterflies
|
const butterflyCount = config.ButterflyCount !== undefined ? config.ButterflyCount : 4; // count of butterflies
|
||||||
const beeCount = config.BeeCount !== undefined ? config.BeeCount : 2; // Number of bees
|
const beeCount = config.BeeCount !== undefined ? config.BeeCount : 2; // count of bees
|
||||||
const ladybugCount = config.LadybugCount !== undefined ? config.LadybugCount : 2; // Number of ladybugs
|
const ladybugCount = config.LadybugCount !== undefined ? config.LadybugCount : 2; // count of ladybugs
|
||||||
const randomSpring = config.EnableRandomSpring !== undefined ? config.EnableRandomSpring : true; // Enable random spring objects
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 2; // Devisor to reduce number of objects on mobile
|
||||||
|
|
||||||
// Credit: https://lottiefiles.com/free-animation/birds-flying-V7O0L8jkOg
|
// Credit: https://lottiefiles.com/free-animation/birds-flying-V7O0L8jkOg
|
||||||
const birdImages = [
|
const birdImages = [
|
||||||
@@ -23,7 +23,10 @@ const butterflyImages = [
|
|||||||
'../Seasonals/Resources/spring_assets/Butterfly_2.gif'
|
'../Seasonals/Resources/spring_assets/Butterfly_2.gif'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Credit: https://lottiefiles.com/free-animation/loading-flying-beee-WcTfIccdJZ
|
||||||
const beeImage = '../Seasonals/Resources/spring_assets/Bee.gif';
|
const beeImage = '../Seasonals/Resources/spring_assets/Bee.gif';
|
||||||
|
|
||||||
|
// Credit: https://pixabay.com/gifs/ladybug-insect-nature-fly-wings-5068/
|
||||||
const ladybugImage = '../Seasonals/Resources/spring_assets/ladybug.gif';
|
const ladybugImage = '../Seasonals/Resources/spring_assets/ladybug.gif';
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
@@ -230,28 +233,35 @@ function initializeSpring() {
|
|||||||
|
|
||||||
const container = document.querySelector('.spring-container');
|
const container = document.querySelector('.spring-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
if (randomSpring) {
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
// Add Pollen
|
let divisor = isMobile ? Math.max(1, symbolCountMobile) : 1;
|
||||||
for (let i = 0; i < pollenCount; i++) {
|
|
||||||
createPollen(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Birds
|
let adjPollen = Math.floor(pollenCount / divisor);
|
||||||
for (let i = 0; i < birdCount; i++) {
|
let adjBird = Math.floor(birdCount / divisor);
|
||||||
setTimeout(() => createBird(container), Math.random() * 1000); // 0-1s desync
|
let adjButterfly = Math.floor(butterflyCount / divisor);
|
||||||
}
|
let adjBee = Math.floor(beeCount / divisor);
|
||||||
// Add Butterflies
|
let adjLadybug = Math.floor(ladybugCount / divisor);
|
||||||
for (let i = 0; i < butterflyCount; i++) {
|
|
||||||
setTimeout(() => createButterfly(container), Math.random() * 1000); // 0-1s desync
|
// Add Pollen
|
||||||
}
|
for (let i = 0; i < adjPollen; i++) {
|
||||||
// Add Bees
|
createPollen(container);
|
||||||
for (let i = 0; i < beeCount; i++) {
|
}
|
||||||
setTimeout(() => createBee(container), Math.random() * 1000); // 0-1s desync
|
|
||||||
}
|
// Add Birds
|
||||||
// Add Ladybugs
|
for (let i = 0; i < adjBird; i++) {
|
||||||
for (let i = 0; i < ladybugCount; i++) {
|
setTimeout(() => createBird(container), Math.random() * 1000); // 0-1s desync
|
||||||
setTimeout(() => createLadybugGif(container), Math.random() * 1000); // 0-1s desync
|
}
|
||||||
}
|
// Add Butterflies
|
||||||
|
for (let i = 0; i < adjButterfly; i++) {
|
||||||
|
setTimeout(() => createButterfly(container), Math.random() * 1000); // 0-1s desync
|
||||||
|
}
|
||||||
|
// Add Bees
|
||||||
|
for (let i = 0; i < adjBee; i++) {
|
||||||
|
setTimeout(() => createBee(container), Math.random() * 1000); // 0-1s desync
|
||||||
|
}
|
||||||
|
// Add Ladybugs
|
||||||
|
for (let i = 0; i < adjLadybug; i++) {
|
||||||
|
setTimeout(() => createLadybugGif(container), Math.random() * 1000); // 0-1s desync
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,7 +305,7 @@ function createBird(container) {
|
|||||||
wrapper.addEventListener('animationend', (e) => {
|
wrapper.addEventListener('animationend', (e) => {
|
||||||
if (e.animationName.includes('fly-')) {
|
if (e.animationName.includes('fly-')) {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
createBird(container);
|
if (document.body.contains(container)) createBird(container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -338,7 +348,7 @@ function createButterfly(container) {
|
|||||||
wrapper.addEventListener('animationend', (e) => {
|
wrapper.addEventListener('animationend', (e) => {
|
||||||
if (e.animationName.includes('fly-')) {
|
if (e.animationName.includes('fly-')) {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
createButterfly(container);
|
if (document.body.contains(container)) createButterfly(container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -385,7 +395,7 @@ function createBee(container) {
|
|||||||
wrapper.addEventListener('animationend', (e) => {
|
wrapper.addEventListener('animationend', (e) => {
|
||||||
if (e.animationName.includes('fly-')) {
|
if (e.animationName.includes('fly-')) {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
createBee(container);
|
if (document.body.contains(container)) createBee(container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -428,7 +438,7 @@ function createLadybugGif(container) {
|
|||||||
wrapper.addEventListener('animationend', (e) => {
|
wrapper.addEventListener('animationend', (e) => {
|
||||||
if (e.animationName.includes('walk-')) {
|
if (e.animationName.includes('walk-')) {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
createLadybugGif(container);
|
if (document.body.contains(container)) createLadybugGif(container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,11 @@
|
|||||||
|
|
||||||
.starwars-center {
|
.starwars-center {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
translate: 0 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.starwars-streak {
|
.starwars-streak {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.StarWars || {};
|
const config = window.SeasonalsPluginConfig?.StarWars || {};
|
||||||
const starwars = config.EnableStarWars !== undefined ? config.EnableStarWars : true;
|
const starwars = config.EnableStarWars !== undefined ? config.EnableStarWars : true; // enable/disable starwars
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Storm || {};
|
const config = window.SeasonalsPluginConfig?.Storm || {};
|
||||||
|
|
||||||
const enabled = config.EnableStorm !== undefined ? config.EnableStorm : true;
|
const enabled = config.EnableStorm !== undefined ? config.EnableStorm : true; // enable/disable storm
|
||||||
const isMobile = window.innerWidth <= 768;
|
const isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300);
|
const elementCount = isMobile ? (config.RaindropCountMobile || 150) : (config.RaindropCount || 300); // count of raindrops
|
||||||
const enableLightning = config.EnableLightning !== undefined ? config.EnableLightning : true;
|
const enableLightning = config.EnableLightning !== undefined ? config.EnableLightning : true; // enable/disable lightning
|
||||||
const rainSpeed = config.RainSpeed || 1.0;
|
const rainSpeed = config.RainSpeed !== undefined ? config.RainSpeed : 1.0; // speed of rain
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Summer || {};
|
const config = window.SeasonalsPluginConfig?.Summer || {};
|
||||||
|
|
||||||
const summer = config.EnableSummer !== undefined ? config.EnableSummer : true; // Enable/disable summer theme
|
const summer = config.EnableSummer !== undefined ? config.EnableSummer : true; // enable/disable summer
|
||||||
const bubbleCount = config.BubbleCount || 30; // Number of bubbles
|
const bubbleCount = config.BubbleCount !== undefined ? config.BubbleCount : 30; // count of bubbles
|
||||||
const dustCount = config.DustCount || 50; // Number of dust particles
|
const dustCount = config.DustCount !== undefined ? config.DustCount : 50; // count of dust particles
|
||||||
const randomSummer = config.EnableRandomSummer !== undefined ? config.EnableRandomSummer : true; // Enable random generating objects
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 2; // Devisor to reduce number of objects on mobile
|
||||||
const randomSummerMobile = config.EnableRandomSummerMobile !== undefined ? config.EnableRandomSummerMobile : false; // Enable random generating objects on mobile
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // Randomize animation duration of bubbles and dust
|
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -39,34 +38,23 @@ observer.observe(document.body, {
|
|||||||
subtree: true,
|
subtree: true,
|
||||||
attributes: true
|
attributes: true
|
||||||
});
|
});
|
||||||
function createBubble(container, isDust = false) {
|
|
||||||
|
function createBubble(container) {
|
||||||
const bubble = document.createElement('div');
|
const bubble = document.createElement('div');
|
||||||
|
|
||||||
if (isDust) {
|
bubble.classList.add('summer-bubble');
|
||||||
bubble.classList.add('summer-dust');
|
|
||||||
} else {
|
|
||||||
bubble.classList.add('summer-bubble');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Random horizontal position
|
// Random horizontal position
|
||||||
const randomLeft = Math.random() * 100;
|
const randomLeft = Math.random() * 100;
|
||||||
bubble.style.left = `${randomLeft}%`;
|
bubble.style.left = `${randomLeft}%`;
|
||||||
|
|
||||||
// Random size
|
// MARK: BUBBLE SIZE
|
||||||
if (!isDust) {
|
const size = Math.random() * 20 + 10; // 10-30px bubbles
|
||||||
// MARK: BUBBLE SIZE
|
bubble.style.width = `${size}px`;
|
||||||
const size = Math.random() * 20 + 10; // 10-30px bubbles
|
bubble.style.height = `${size}px`;
|
||||||
bubble.style.width = `${size}px`;
|
|
||||||
bubble.style.height = `${size}px`;
|
|
||||||
} else {
|
|
||||||
// MARK: DUST SIZE
|
|
||||||
const size = Math.random() * 3 + 1; // 1-4px dust
|
|
||||||
bubble.style.width = `${size}px`;
|
|
||||||
bubble.style.height = `${size}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animation properties
|
// Animation properties
|
||||||
const duration = isDust ? (Math.random() * 20 + 10) : (Math.random() * 10 + 5); // Dust is slower
|
const duration = (Math.random() * 10 + 5);
|
||||||
const delay = Math.random() * 10;
|
const delay = Math.random() * 10;
|
||||||
|
|
||||||
if (enableDifferentDuration) {
|
if (enableDifferentDuration) {
|
||||||
@@ -77,19 +65,30 @@ function createBubble(container, isDust = false) {
|
|||||||
container.appendChild(bubble);
|
container.appendChild(bubble);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRandomSummerObjects() {
|
function createDust(container) {
|
||||||
const container = document.querySelector('.summer-container');
|
const dust = document.createElement('div');
|
||||||
if (!container) return;
|
|
||||||
|
dust.classList.add('summer-dust');
|
||||||
|
|
||||||
|
// Random horizontal position
|
||||||
|
const randomLeft = Math.random() * 100;
|
||||||
|
dust.style.left = `${randomLeft}%`;
|
||||||
|
|
||||||
|
// MARK: DUST SIZE
|
||||||
|
const size = Math.random() * 3 + 1; // 1-4px dust
|
||||||
|
dust.style.width = `${size}px`;
|
||||||
|
dust.style.height = `${size}px`;
|
||||||
|
|
||||||
|
// Animation properties
|
||||||
|
const duration = (Math.random() * 20 + 10); // Dust is slower
|
||||||
|
const delay = Math.random() * 10;
|
||||||
|
|
||||||
// Add bubbles
|
if (enableDifferentDuration) {
|
||||||
for (let i = 0; i < bubbleCount; i++) {
|
dust.style.animationDuration = `${duration}s`;
|
||||||
createBubble(container, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some dust particles
|
|
||||||
for (let i = 0; i < dustCount; i++) {
|
|
||||||
createBubble(container, true);
|
|
||||||
}
|
}
|
||||||
|
dust.style.animationDelay = `${delay}s`;
|
||||||
|
|
||||||
|
container.appendChild(dust);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSummerObjects() {
|
function initSummerObjects() {
|
||||||
@@ -101,38 +100,18 @@ function initSummerObjects() {
|
|||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial bubbles/dust
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
for (let i = 0; i < 10; i++) {
|
let limitBubbles = isMobile ? Math.floor(bubbleCount / Math.max(1, symbolCountMobile)) : bubbleCount;
|
||||||
const bubble = document.createElement('div');
|
let limitDust = isMobile ? Math.floor(dustCount / Math.max(1, symbolCountMobile)) : dustCount;
|
||||||
const isDust = Math.random() > 0.5;
|
|
||||||
if (isDust) {
|
// Initial bubbles
|
||||||
bubble.classList.add('summer-dust');
|
for (let i = 0; i < limitBubbles; i++) {
|
||||||
} else {
|
createBubble(container);
|
||||||
bubble.classList.add('summer-bubble');
|
}
|
||||||
}
|
|
||||||
|
// Initial dust
|
||||||
const randomLeft = Math.random() * 100;
|
for (let i = 0; i < limitDust; i++) {
|
||||||
bubble.style.left = `${randomLeft}%`;
|
createDust(container);
|
||||||
|
|
||||||
if (!isDust) {
|
|
||||||
// MARK: BUBBLE SIZE
|
|
||||||
const size = Math.random() * 20 + 10;
|
|
||||||
bubble.style.width = `${size}px`;
|
|
||||||
bubble.style.height = `${size}px`;
|
|
||||||
} else {
|
|
||||||
// MARK: DUST SIZE
|
|
||||||
const size = Math.random() * 3 + 1;
|
|
||||||
bubble.style.width = `${size}px`;
|
|
||||||
bubble.style.height = `${size}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const duration = isDust ? (Math.random() * 20 + 10) : (Math.random() * 10 + 5);
|
|
||||||
if (enableDifferentDuration) {
|
|
||||||
bubble.style.animationDuration = `${duration}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
bubble.style.animationDelay = `-${Math.random() * 10}s`;
|
|
||||||
container.appendChild(bubble);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,11 +119,6 @@ function initializeSummer() {
|
|||||||
if (!summer) return;
|
if (!summer) return;
|
||||||
initSummerObjects();
|
initSummerObjects();
|
||||||
toggleSummer();
|
toggleSummer();
|
||||||
|
|
||||||
const screenWidth = window.innerWidth;
|
|
||||||
if (randomSummer && (screenWidth > 768 || randomSummerMobile)) {
|
|
||||||
addRandomSummerObjects();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeSummer();
|
initializeSummer();
|
||||||
|
|||||||
@@ -235,41 +235,41 @@
|
|||||||
<label for="theme-select">Theme:</label>
|
<label for="theme-select">Theme:</label>
|
||||||
<select id="theme-select">
|
<select id="theme-select">
|
||||||
<option value="" selected disabled>— Select a theme —</option>
|
<option value="" selected disabled>— Select a theme —</option>
|
||||||
|
<option value="autumn">Autumn</option>
|
||||||
|
<option value="birthday">Birthday</option>
|
||||||
|
<option value="carnival">Carnival (Confetti)</option>
|
||||||
|
<option value="cherryblossom">Cherryblossom</option>
|
||||||
|
<option value="christmas">Christmas</option>
|
||||||
|
<option value="earthday">Earth Day</option>
|
||||||
|
<option value="easter">Easter</option>
|
||||||
|
<option value="eid">Eid al-Fitr</option>
|
||||||
|
<option value="eurovision">Eurovision</option>
|
||||||
|
<option value="filmnoir">Film-Noir</option>
|
||||||
|
<option value="fireworks">Fireworks</option>
|
||||||
|
<option value="frost">Frost / Ice</option>
|
||||||
|
<option value="friday13">Friday the 13th</option>
|
||||||
|
<option value="halloween">Halloween</option>
|
||||||
|
<option value="hearts">Hearts</option>
|
||||||
|
<option value="marioday">Mario Day</option>
|
||||||
|
<option value="matrix">Matrix</option>
|
||||||
|
<option value="oktoberfest">Oktoberfest</option>
|
||||||
|
<option value="olympia">Olympia</option>
|
||||||
|
<option value="oscar">Oscar Awards</option>
|
||||||
|
<option value="pride">Pride</option>
|
||||||
|
<option value="rain">Rain</option>
|
||||||
|
<option value="resurrection">Resurrection</option>
|
||||||
|
<option value="santa">Santa</option>
|
||||||
<option value="snowfall">Snowfall</option>
|
<option value="snowfall">Snowfall</option>
|
||||||
<option value="snowflakes">Snowflakes</option>
|
<option value="snowflakes">Snowflakes</option>
|
||||||
<option value="snowstorm">Snowstorm</option>
|
<option value="snowstorm">Snowstorm</option>
|
||||||
<option value="fireworks">Fireworks</option>
|
|
||||||
<option value="halloween">Halloween</option>
|
|
||||||
<option value="spooky">Spooky</option>
|
|
||||||
<option value="hearts">Hearts</option>
|
|
||||||
<option value="christmas">Christmas</option>
|
|
||||||
<option value="santa">Santa</option>
|
|
||||||
<option value="autumn">Autumn</option>
|
|
||||||
<option value="easter">Easter</option>
|
|
||||||
<option value="resurrection">Resurrection</option>
|
|
||||||
<option value="spring">Spring</option>
|
|
||||||
<option value="summer">Summer (Bubbles)</option>
|
|
||||||
<option value="carnival">Carnival (Confetti)</option>
|
|
||||||
<option value="cherryblossom">Cherryblossom</option>
|
|
||||||
<option value="earthday">Earth Day</option>
|
|
||||||
<option value="eurovision">Eurovision</option>
|
|
||||||
<option value="matrix">Matrix</option>
|
|
||||||
<option value="pride">Pride</option>
|
|
||||||
<option value="rain">Rain</option>
|
|
||||||
<option value="storm">Storm (⚠️Epilepsy Warning)</option>
|
|
||||||
<option value="frost">Frost / Ice</option>
|
|
||||||
<option value="filmnoir">Film-Noir</option>
|
|
||||||
<option value="oscar">Oscar Awards</option>
|
|
||||||
<option value="marioday">Mario Day</option>
|
|
||||||
<option value="starwars">Star Wars Day</option>
|
|
||||||
<option value="oktoberfest">Oktoberfest</option>
|
|
||||||
<option value="friday13">Friday the 13th</option>
|
|
||||||
<option value="eid">Eid al-Fitr</option>
|
|
||||||
<option value="sports">Sports / Football</option>
|
|
||||||
<option value="olympia">Olympia / Games</option>
|
|
||||||
<option value="space">Space / Sci-Fi</option>
|
<option value="space">Space / Sci-Fi</option>
|
||||||
|
<option value="spooky">Spooky</option>
|
||||||
|
<option value="sports">Sports</option>
|
||||||
|
<option value="spring">Spring</option>
|
||||||
|
<option value="starwars">Star Wars Day</option>
|
||||||
|
<option value="storm">Storm (⚠️Epilepsy Warning⚠️)</option>
|
||||||
|
<option value="summer">Summer (Bubbles)</option>
|
||||||
<option value="underwater">Underwater</option>
|
<option value="underwater">Underwater</option>
|
||||||
<option value="birthday">Birthday</option>
|
|
||||||
<option value="custom">⚙ Custom (Local Files)</option>
|
<option value="custom">⚙ Custom (Local Files)</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -341,41 +341,41 @@
|
|||||||
|
|
||||||
// ── Built-in theme map (local file paths for testing) ──
|
// ── Built-in theme map (local file paths for testing) ──
|
||||||
const themes = {
|
const themes = {
|
||||||
snowfall: { css: 'snowfall.css', js: 'snowfall.js', container: 'snowfall-container' },
|
|
||||||
snowflakes: { css: 'snowflakes.css', js: 'snowflakes.js', container: 'snowflakes' },
|
|
||||||
snowstorm: { css: 'snowstorm.css', js: 'snowstorm.js', container: 'snowstorm-container' },
|
|
||||||
fireworks: { css: 'fireworks.css', js: 'fireworks.js', container: 'fireworks' },
|
|
||||||
halloween: { css: 'halloween.css', js: 'halloween.js', container: 'halloween-container' },
|
|
||||||
spooky: { css: 'spooky.css', js: 'spooky.js', container: 'spooky-container' },
|
|
||||||
hearts: { css: 'hearts.css', js: 'hearts.js', container: 'hearts-container' },
|
|
||||||
christmas: { css: 'christmas.css', js: 'christmas.js', container: 'christmas-container' },
|
|
||||||
santa: { css: 'santa.css', js: 'santa.js', container: 'santa-container' },
|
|
||||||
autumn: { css: 'autumn.css', js: 'autumn.js', container: 'autumn-container' },
|
autumn: { css: 'autumn.css', js: 'autumn.js', container: 'autumn-container' },
|
||||||
easter: { css: 'easter.css', js: 'easter.js', container: 'easter-container' },
|
birthday: { css: 'birthday.css', js: 'birthday.js', container: 'birthday-container' },
|
||||||
resurrection: { css: 'resurrection.css', js: 'resurrection.js', container: 'resurrection-container' },
|
|
||||||
spring: { css: 'spring.css', js: 'spring.js', container: 'spring-container' },
|
|
||||||
summer: { css: 'summer.css', js: 'summer.js', container: 'summer-container' },
|
|
||||||
carnival: { css: 'carnival.css', js: 'carnival.js', container: 'carnival-container' },
|
carnival: { css: 'carnival.css', js: 'carnival.js', container: 'carnival-container' },
|
||||||
cherryblossom: { css: 'cherryblossom.css', js: 'cherryblossom.js', container: 'cherryblossom-container' },
|
cherryblossom:{ css: 'cherryblossom.css', js: 'cherryblossom.js',container: 'cherryblossom-container' },
|
||||||
|
christmas: { css: 'christmas.css', js: 'christmas.js', container: 'christmas-container' },
|
||||||
earthday: { css: 'earthday.css', js: 'earthday.js', container: 'earthday-container' },
|
earthday: { css: 'earthday.css', js: 'earthday.js', container: 'earthday-container' },
|
||||||
|
easter: { css: 'easter.css', js: 'easter.js', container: 'easter-container' },
|
||||||
|
eid: { css: 'eid.css', js: 'eid.js', container: 'eid-container' },
|
||||||
eurovision: { css: 'eurovision.css', js: 'eurovision.js', container: 'eurovision-container' },
|
eurovision: { css: 'eurovision.css', js: 'eurovision.js', container: 'eurovision-container' },
|
||||||
matrix: { css: 'matrix.css', js: 'matrix.js', container: 'matrix-container' },
|
filmnoir: { css: 'filmnoir.css', js: 'filmnoir.js', container: 'filmnoir-container' },
|
||||||
|
fireworks: { css: 'fireworks.css', js: 'fireworks.js', container: 'fireworks' },
|
||||||
|
frost: { css: 'frost.css', js: 'frost.js', container: 'frost-container' },
|
||||||
|
friday13: { css: 'friday13.css', js: 'friday13.js', container: 'friday13-container' },
|
||||||
|
halloween: { css: 'halloween.css', js: 'halloween.js', container: 'halloween-container' },
|
||||||
|
hearts: { css: 'hearts.css', js: 'hearts.js', container: 'hearts-container' },
|
||||||
|
marioday: { css: 'marioday.css', js: 'marioday.js', container: 'marioday-container' },
|
||||||
|
matrix: { css: 'matrix.css', js: 'matrix.js', container: 'matrix-container' },
|
||||||
|
oktoberfest: { css: 'oktoberfest.css', js: 'oktoberfest.js', container: 'oktoberfest-container' },
|
||||||
|
olympia: { css: 'olympia.css', js: 'olympia.js', container: 'olympia-container' },
|
||||||
|
oscar: { css: 'oscar.css', js: 'oscar.js', container: 'oscar-container' },
|
||||||
pride: { css: 'pride.css', js: 'pride.js', container: 'pride-container' },
|
pride: { css: 'pride.css', js: 'pride.js', container: 'pride-container' },
|
||||||
rain: { css: 'rain.css', js: 'rain.js', container: 'rain-container' },
|
rain: { css: 'rain.css', js: 'rain.js', container: 'rain-container' },
|
||||||
storm: { css: 'storm.css', js: 'storm.js', container: 'storm-container' },
|
resurrection: { css: 'resurrection.css', js: 'resurrection.js', container: 'resurrection-container' },
|
||||||
frost: { css: 'frost.css', js: 'frost.js', container: 'frost-container' },
|
santa: { css: 'santa.css', js: 'santa.js', container: 'santa-container' },
|
||||||
filmnoir: { css: 'filmnoir.css', js: 'filmnoir.js', container: 'filmnoir-container' },
|
snowfall: { css: 'snowfall.css', js: 'snowfall.js', container: 'snowfall-container' },
|
||||||
oscar: { css: 'oscar.css', js: 'oscar.js', container: 'oscar-container' },
|
snowflakes: { css: 'snowflakes.css', js: 'snowflakes.js', container: 'snowflakes' },
|
||||||
marioday: { css: 'marioday.css', js: 'marioday.js', container: 'marioday-container' },
|
snowstorm: { css: 'snowstorm.css', js: 'snowstorm.js', container: 'snowstorm-container' },
|
||||||
starwars: { css: 'starwars.css', js: 'starwars.js', container: 'starwars-container' },
|
|
||||||
oktoberfest: { css: 'oktoberfest.css', js: 'oktoberfest.js', container: 'oktoberfest-container' },
|
|
||||||
friday13: { css: 'friday13.css', js: 'friday13.js', container: 'friday13-container' },
|
|
||||||
eid: { css: 'eid.css', js: 'eid.js', container: 'eid-container' },
|
|
||||||
sports: { css: 'sports.css', js: 'sports.js', container: 'sports-container' },
|
|
||||||
olympia: { css: 'olympia.css', js: 'olympia.js', container: 'olympia-container' },
|
|
||||||
space: { css: 'space.css', js: 'space.js', container: 'space-container' },
|
space: { css: 'space.css', js: 'space.js', container: 'space-container' },
|
||||||
underwater: { css: 'underwater.css', js: 'underwater.js', container: 'underwater-container' },
|
spooky: { css: 'spooky.css', js: 'spooky.js', container: 'spooky-container' },
|
||||||
birthday: { css: 'birthday.css', js: 'birthday.js', container: 'birthday-container' }
|
sports: { css: 'sports.css', js: 'sports.js', container: 'sports-container' },
|
||||||
|
spring: { css: 'spring.css', js: 'spring.js', container: 'spring-container' },
|
||||||
|
starwars: { css: 'starwars.css', js: 'starwars.js', container: 'starwars-container' },
|
||||||
|
storm: { css: 'storm.css', js: 'storm.js', container: 'storm-container' },
|
||||||
|
summer: { css: 'summer.css', js: 'summer.js', container: 'summer-container' },
|
||||||
|
underwater: { css: 'underwater.css', js: 'underwater.js', container: 'underwater-container' }
|
||||||
};
|
};
|
||||||
|
|
||||||
const select = document.getElementById('theme-select');
|
const select = document.getElementById('theme-select');
|
||||||
@@ -511,11 +511,11 @@
|
|||||||
const container = document.querySelector('.seasonals-container');
|
const container = document.querySelector('.seasonals-container');
|
||||||
container.className = `seasonals-container ${containerClass}`;
|
container.className = `seasonals-container ${containerClass}`;
|
||||||
|
|
||||||
// Inject CSS
|
// Inject CSS with cache-buster
|
||||||
if (cssFile) {
|
if (cssFile) {
|
||||||
const link = document.createElement('link');
|
const link = document.createElement('link');
|
||||||
link.rel = 'stylesheet';
|
link.rel = 'stylesheet';
|
||||||
link.href = cssFile;
|
link.href = cssFile + '?v=' + new Date().getTime();
|
||||||
link.setAttribute('data-seasonal', 'true');
|
link.setAttribute('data-seasonal', 'true');
|
||||||
link.onerror = () => console.error(`[Test Site] Failed to load CSS: ${cssFile}`);
|
link.onerror = () => console.error(`[Test Site] Failed to load CSS: ${cssFile}`);
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
@@ -525,7 +525,7 @@
|
|||||||
if (jsFile) {
|
if (jsFile) {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(jsFile);
|
const response = await fetch(jsFile + '?v=' + new Date().getTime());
|
||||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||||
const code = await response.text();
|
const code = await response.text();
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.underwater-seaweed {
|
.underwater-seaweed {
|
||||||
|
will-change: transform, opacity;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1vh;
|
bottom: -1vh;
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.underwater-bubble {
|
.underwater-bubble {
|
||||||
|
will-change: transform;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -5vh;
|
bottom: -5vh;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -62,16 +64,29 @@
|
|||||||
z-index: 40;
|
z-index: 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes underwater-swim-right {
|
@keyframes underwater-traverse-right {
|
||||||
0% { transform: translateX(0) translateY(0) scaleX(-1); }
|
0% { left: -25vw; }
|
||||||
50% { transform: translateX(65vw) translateY(-5vh) scaleX(-1); }
|
100% { left: 125vw; }
|
||||||
100% { transform: translateX(130vw) translateY(0) scaleX(-1); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes underwater-swim-left {
|
@keyframes underwater-traverse-left {
|
||||||
0% { transform: translateX(0) translateY(0); }
|
0% { left: 125vw; }
|
||||||
50% { transform: translateX(-65vw) translateY(5vh); }
|
100% { left: -25vw; }
|
||||||
100% { transform: translateX(-130vw) translateY(0); }
|
}
|
||||||
|
|
||||||
|
@keyframes underwater-traverse-up {
|
||||||
|
0% { top: 0; translate: 0 120vh; }
|
||||||
|
100% { top: 0; translate: 0 -20vh; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes underwater-traverse-down {
|
||||||
|
0% { top: 0; translate: 0 -20vh; }
|
||||||
|
100% { top: 0; translate: 0 120vh; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes underwater-sway-y {
|
||||||
|
0% { transform: translateY(-2vh); }
|
||||||
|
100% { transform: translateY(2vh); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes underwater-sway {
|
@keyframes underwater-sway {
|
||||||
@@ -86,3 +101,32 @@
|
|||||||
90% { opacity: 0; }
|
90% { opacity: 0; }
|
||||||
100% { transform: translateY(-110vh) translateX(10px); opacity: 0; }
|
100% { transform: translateY(-110vh) translateX(10px); opacity: 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.underwater-god-rays {
|
||||||
|
will-change: transform;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -50vw;
|
||||||
|
width: 200vw;
|
||||||
|
height: 200vh;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
15deg,
|
||||||
|
rgba(255, 255, 255, 0.02) 0px,
|
||||||
|
rgba(255, 255, 255, 0.05) 100px,
|
||||||
|
transparent 100px,
|
||||||
|
transparent 300px
|
||||||
|
);
|
||||||
|
animation: god-rays-sway 20s ease-in-out infinite alternate;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 12;
|
||||||
|
transform-origin: top center;
|
||||||
|
mix-blend-mode: overlay;
|
||||||
|
filter: blur(5px);
|
||||||
|
translate: 0 -50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes god-rays-sway {
|
||||||
|
0% { transform: rotate(-3deg) translateX(-5%); opacity: 0.4; }
|
||||||
|
50% { opacity: 0.8; }
|
||||||
|
100% { transform: rotate(3deg) translateX(5%); opacity: 0.4; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,109 @@
|
|||||||
const config = window.SeasonalsPluginConfig?.Underwater || {};
|
const config = window.SeasonalsPluginConfig?.Underwater || {};
|
||||||
|
|
||||||
const underwater = config.EnableUnderwater !== undefined ? config.EnableUnderwater : true;
|
const underwater = config.EnableUnderwater !== undefined ? config.EnableUnderwater : true; // enable/disable underwater
|
||||||
const symbolCount = config.SymbolCount || 15;
|
const symbolCountMobile = config.SymbolCountMobile !== undefined ? config.SymbolCountMobile : 2; // Devisor to reduce number of objects on mobile
|
||||||
const useRandomSymbols = config.EnableRandomSymbols !== undefined ? config.EnableRandomSymbols : true;
|
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true; // enable different durations
|
||||||
const enableRandomMobile = config.EnableRandomSymbolsMobile !== undefined ? config.EnableRandomSymbolsMobile : false;
|
const enableLightRays = config.EnableLightRays !== undefined ? config.EnableLightRays : true; // enable/disable lightrays
|
||||||
const enableDifferentDuration = config.EnableDifferentDuration !== undefined ? config.EnableDifferentDuration : true;
|
const seaweedCount = config.SeaweedCount !== undefined ? config.SeaweedCount : 50; // count of seaweed
|
||||||
|
|
||||||
|
// Entity counts configured
|
||||||
|
const fishCount = config.FishCount !== undefined ? config.FishCount : 15; // count of fish
|
||||||
|
const seahorseCount = config.SeahorseCount !== undefined ? config.SeahorseCount : 3; // count of seahorse
|
||||||
|
const jellyfishCount = config.JellyfishCount !== undefined ? config.JellyfishCount : 3; // count of jellyfish
|
||||||
|
const turtleCount = config.TurtleCount !== undefined ? config.TurtleCount : 1; // count of turtle
|
||||||
|
const crabCount = config.CrabCount !== undefined ? config.CrabCount : 2; // count of crab
|
||||||
|
const starfishCount = config.StarfishCount !== undefined ? config.StarfishCount : 2; // count of starfish
|
||||||
|
const shellCount = config.ShellCount !== undefined ? config.ShellCount : 2; // count of shell
|
||||||
|
|
||||||
|
// credits: https://lottiefiles.com/free-animation/seaweed-E6Go0HdkqY
|
||||||
|
const seaweeds = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/seaweed_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/seaweed_2.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-krebs-bild-0041-59970.htm
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-krebs-bild-0002-59931.htm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const crabImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/crab_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/crab_2.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/crab_3.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://lottiefiles.com/free-animation/dancing-starfish-tJ9ZFu9Zq0
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0003-50003.htm
|
||||||
|
*/
|
||||||
|
const starfishImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/starfish_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/starfish_2.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Credit: https://www.animierte-gifs.net/img-animiertes-muschel-bild-0021-108539.htm
|
||||||
|
const shellImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/shell_1.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://lottiefiles.com/free-animation/0101uwt-tt-01-4fA4Lm9gtN
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0473-50473.htm
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0290-50290.htm
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0049-50049.htm
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0403-50403.htm
|
||||||
|
*
|
||||||
|
* https://flaticon.com
|
||||||
|
*/
|
||||||
|
const fishImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_2.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_3.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_5.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_6.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_7.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_8.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_9.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_10.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_11.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_12.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_13.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_14.png",
|
||||||
|
"../Seasonals/Resources/underwater_assets/fish_15.png"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credits:
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0221-50221.htm
|
||||||
|
* https://www.animierte-gifs.net/img-animiertes-fische-bild-0217-50217.htm
|
||||||
|
*/
|
||||||
|
const seahorsesImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/seahorse_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/seahorse_2.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// credit: https://lottiefiles.com/free-animation/sea-turtle-s0sbHIWS2F
|
||||||
|
const turtleImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/turtle.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// credits: https://lottiefiles.com/free-animation/jellyfish-wPwyF8EeSQ
|
||||||
|
const jellyfishImages = [
|
||||||
|
"../Seasonals/Resources/underwater_assets/jellyfish_1.gif",
|
||||||
|
"../Seasonals/Resources/underwater_assets/jellyfish_2.gif"
|
||||||
|
];
|
||||||
|
|
||||||
|
// MARK: Base sizes for all creatures (in vh)
|
||||||
|
const seahorseSize = 8;
|
||||||
|
const turtleSize = 14;
|
||||||
|
const jellyfishSize = 18;
|
||||||
|
const fishSize = 8;
|
||||||
|
const crabSize = 4;
|
||||||
|
const starfishSize = 4;
|
||||||
|
const shellSize = 7;
|
||||||
|
|
||||||
let msgPrinted = false;
|
let msgPrinted = false;
|
||||||
|
|
||||||
@@ -46,100 +145,191 @@ function createUnderwater() {
|
|||||||
container.className = 'underwater-container';
|
container.className = 'underwater-container';
|
||||||
container.setAttribute("aria-hidden", "true");
|
container.setAttribute("aria-hidden", "true");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
|
} else {
|
||||||
|
container.innerHTML = ''; // Prevent infinite duplication on theme reload!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deep blue overlay
|
// Deep blue overlay
|
||||||
const bg = document.createElement('div');
|
const bg = document.createElement('div');
|
||||||
bg.className = 'underwater-bg';
|
bg.className = 'underwater-bg';
|
||||||
container.appendChild(bg);
|
container.appendChild(bg);
|
||||||
|
|
||||||
const standardCount = 8;
|
|
||||||
const totalSymbols = symbolCount + standardCount;
|
|
||||||
|
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
// Light Rays (God Rays)
|
||||||
let finalCount = totalSymbols;
|
if (enableLightRays) {
|
||||||
|
const rays = document.createElement('div');
|
||||||
if (isMobile) {
|
rays.className = 'underwater-god-rays';
|
||||||
finalCount = enableRandomMobile ? totalSymbols : standardCount;
|
container.appendChild(rays);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRandomDuration = enableDifferentDuration !== false;
|
const useRandomDuration = enableDifferentDuration !== false;
|
||||||
|
let isMobile = window.matchMedia("only screen and (max-width: 768px)").matches;
|
||||||
|
|
||||||
// Seaweed swaying at the bottom
|
// Seaweed swaying at the bottom (evenly distributed based on count)
|
||||||
for (let i = 0; i < 4; i++) {
|
const activeSeaweedCount = isMobile ? Math.max(1, Math.floor(seaweedCount / Math.max(1, symbolCountMobile))) : Math.max(1, seaweedCount);
|
||||||
|
const seaweedSpacing = 95 / activeSeaweedCount;
|
||||||
|
for (let i = 0; i < activeSeaweedCount; i++) {
|
||||||
let seaweed = document.createElement('div');
|
let seaweed = document.createElement('div');
|
||||||
seaweed.className = 'underwater-seaweed';
|
seaweed.className = 'underwater-seaweed';
|
||||||
seaweed.style.left = `${10 + (i * 25)}vw`;
|
seaweed.style.position = 'absolute';
|
||||||
|
|
||||||
|
// Distance from the bottom edge for the seaweed
|
||||||
|
seaweed.style.bottom = '-18px';
|
||||||
|
|
||||||
|
let offset = (Math.random() * seaweedSpacing) - (seaweedSpacing / 2);
|
||||||
|
seaweed.style.left = `max(0vw, min(95vw, calc(${(i * seaweedSpacing)}vw + ${offset}vw)))`;
|
||||||
seaweed.style.animationDelay = `-${Math.random() * 5}s`;
|
seaweed.style.animationDelay = `-${Math.random() * 5}s`;
|
||||||
|
|
||||||
// Randomly flip
|
// Random parallax scale for seaweed depth
|
||||||
if (Math.random() > 0.5) {
|
const depth = Math.random();
|
||||||
seaweed.style.transform = 'scaleX(-1)';
|
const scale = 0.5 + depth * 0.7; // 0.5 to 1.2
|
||||||
}
|
const blur = depth < 0.3 ? `blur(2px)` : 'none';
|
||||||
|
seaweed.style.filter = blur;
|
||||||
|
|
||||||
|
let flip = Math.random() > 0.5 ? 'scaleX(-1)' : 'scaleX(1)';
|
||||||
|
seaweed.style.transform = `scale(${scale}) ${flip}`;
|
||||||
|
seaweed.style.zIndex = depth < 0.5 ? '15' : '30';
|
||||||
|
|
||||||
let img = document.createElement('img');
|
// Mix Emojis and GIFs for seaweed
|
||||||
img.src = '../Seasonals/Resources/underwater_images/seaweed.png';
|
if (Math.random() > 0.4) {
|
||||||
img.onerror = function() {
|
let img = document.createElement('img');
|
||||||
this.style.display = 'none';
|
img.src = seaweeds[Math.floor(Math.random() * seaweeds.length)];
|
||||||
this.parentElement.innerHTML = '🌿';
|
img.onerror = function() {
|
||||||
this.parentElement.style.fontSize = '3rem';
|
this.style.display = 'none';
|
||||||
this.parentElement.style.bottom = '0';
|
};
|
||||||
this.parentElement.style.transformOrigin = 'bottom center';
|
seaweed.appendChild(img);
|
||||||
};
|
} else {
|
||||||
seaweed.appendChild(img);
|
seaweed.innerHTML = '🌿';
|
||||||
|
seaweed.style.fontSize = '3rem';
|
||||||
|
seaweed.style.bottom = '0';
|
||||||
|
seaweed.style.transformOrigin = 'bottom center';
|
||||||
|
}
|
||||||
container.appendChild(seaweed);
|
container.appendChild(seaweed);
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeItems = ['fish_orange', 'fish_blue', 'jellyfish', 'turtle'];
|
// Static Bottom Creatures logic
|
||||||
|
function spawnStatic(imageArray, maxCount, baseSize) {
|
||||||
|
let spawnLimit = isMobile ? Math.floor(maxCount / Math.max(1, symbolCountMobile)) : maxCount;
|
||||||
|
for (let i = 0; i < spawnLimit; i++) {
|
||||||
|
let creature = document.createElement('div');
|
||||||
|
creature.className = 'underwater-static-bottom';
|
||||||
|
creature.style.position = 'absolute';
|
||||||
|
creature.style.bottom = '5px';
|
||||||
|
creature.style.left = `${Math.random() * 95}vw`;
|
||||||
|
creature.style.zIndex = '20'; // In between seaweed layers
|
||||||
|
|
||||||
for (let i = 0; i < finalCount; i++) {
|
let img = document.createElement('img');
|
||||||
let symbol = document.createElement('div');
|
img.src = imageArray[Math.floor(Math.random() * imageArray.length)];
|
||||||
|
img.style.height = `${baseSize}vh`;
|
||||||
|
|
||||||
|
// Random scale variance and flip
|
||||||
|
const scale = 0.7 + Math.random() * 0.5; // 0.7 to 1.2 x baseSize
|
||||||
|
const flip = Math.random() > 0.5 ? 'scaleX(-1)' : 'scaleX(1)';
|
||||||
|
img.style.transform = `scale(${scale}) ${flip}`;
|
||||||
|
|
||||||
|
img.onerror = function() {
|
||||||
|
this.style.display = 'none';
|
||||||
|
};
|
||||||
|
creature.appendChild(img);
|
||||||
|
container.appendChild(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnStatic(crabImages, crabCount, crabSize);
|
||||||
|
spawnStatic(starfishImages, starfishCount, starfishSize);
|
||||||
|
spawnStatic(shellImages, shellCount, shellSize);
|
||||||
|
|
||||||
|
// Swimmers logic
|
||||||
|
function spawnSwimmerLoop(imageArray, maxCount, baseSize, typeName) {
|
||||||
|
if (maxCount <= 0) return;
|
||||||
|
let spawnLimit = isMobile ? Math.floor(maxCount / Math.max(1, symbolCountMobile)) : maxCount;
|
||||||
|
|
||||||
const randomItem = activeItems[Math.floor(Math.random() * activeItems.length)];
|
for (let i = 0; i < spawnLimit; i++) {
|
||||||
symbol.className = `underwater-symbol underwater-${randomItem}`;
|
spawnSingleSwimmer(imageArray, baseSize, typeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawnSingleSwimmer(imageArray, baseSize, typeName) {
|
||||||
|
if (!document.querySelector('.underwater-container')) return;
|
||||||
|
|
||||||
|
let symbol = document.createElement('div');
|
||||||
|
symbol.className = `underwater-symbol`;
|
||||||
|
|
||||||
|
const randomImage = imageArray[Math.floor(Math.random() * imageArray.length)];
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = `../Seasonals/Resources/underwater_images/${randomItem}.png`;
|
img.src = randomImage;
|
||||||
|
img.style.height = `${baseSize}vh`;
|
||||||
|
img.style.width = 'auto';
|
||||||
|
img.style.maxWidth = 'none';
|
||||||
|
|
||||||
img.onerror = function() {
|
img.onerror = function() {
|
||||||
this.style.display = 'none';
|
this.style.display = 'none';
|
||||||
this.parentElement.innerHTML = getUnderwaterEmojiFallback(randomItem);
|
|
||||||
};
|
};
|
||||||
symbol.appendChild(img);
|
|
||||||
|
|
||||||
const topPos = 10 + Math.random() * 80; // 10 to 90vh
|
const depth = Math.random();
|
||||||
const delaySeconds = Math.random() * 10;
|
const distanceScale = 0.4 + (depth * 0.8);
|
||||||
|
const blurAmount = depth < 0.4 ? (1 - depth) * 3 : 0;
|
||||||
|
const opacity = 0.4 + (depth * 0.5);
|
||||||
|
|
||||||
let durationSeconds = 15;
|
symbol.style.opacity = `${opacity}`;
|
||||||
if (useRandomDuration) {
|
symbol.style.filter = `blur(${blurAmount}px)`;
|
||||||
durationSeconds = Math.random() * 10 + 15; // 15 to 25 seconds slow swimming
|
symbol.style.zIndex = Math.floor(depth * 30) + 10;
|
||||||
}
|
|
||||||
|
symbol.style.animationIterationCount = 'infinite';
|
||||||
|
|
||||||
// Randomly pick direction: left-to-right OR right-to-left
|
let durationSeconds = (1 - depth) * 20 + 15 + Math.random() * 5;
|
||||||
const goRight = Math.random() > 0.5;
|
if (!useRandomDuration) durationSeconds = 20;
|
||||||
if (goRight) {
|
|
||||||
symbol.style.animationName = 'underwater-swim-right';
|
// Apply a negative delay on spawn so they start mid-screen scattered
|
||||||
symbol.style.left = '-10vw';
|
const startDelay = -(Math.random() * durationSeconds);
|
||||||
|
|
||||||
|
// Animate based on type
|
||||||
|
if (typeName === 'jellyfish') {
|
||||||
|
const goUp = Math.random() > 0.5;
|
||||||
|
symbol.style.animationName = goUp ? 'underwater-traverse-up' : 'underwater-traverse-down';
|
||||||
|
symbol.style.left = `${Math.random() * 90}vw`;
|
||||||
|
|
||||||
|
const flip = Math.random() > 0.5 ? 'scaleX(-1)' : 'scaleX(1)';
|
||||||
|
symbol.style.transform = `scale(${distanceScale}) ${flip}`;
|
||||||
|
|
||||||
|
durationSeconds *= 0.8;
|
||||||
|
symbol.style.animationDuration = `${durationSeconds}s`;
|
||||||
|
symbol.style.animationDelay = `${startDelay}s`;
|
||||||
|
|
||||||
|
symbol.appendChild(img);
|
||||||
} else {
|
} else {
|
||||||
symbol.style.animationName = 'underwater-swim-left';
|
const goRight = Math.random() > 0.5;
|
||||||
symbol.style.right = '-10vw';
|
const directionScale = goRight ? 'scaleX(-1)' : 'scaleX(1)';
|
||||||
symbol.style.transform = 'scaleX(-1)'; // flip fish to face left
|
|
||||||
|
symbol.style.animationName = goRight ? 'underwater-traverse-right' : 'underwater-traverse-left';
|
||||||
|
symbol.style.animationDelay = `${startDelay}s`;
|
||||||
|
|
||||||
|
const rotationDiv = document.createElement('div');
|
||||||
|
let swayDur = Math.random() * 2 + 2;
|
||||||
|
if (typeName === 'seahorse') swayDur *= 1.5;
|
||||||
|
else if (typeName === 'turtle') swayDur *= 2;
|
||||||
|
|
||||||
|
rotationDiv.style.animation = `underwater-sway-y ${swayDur}s ease-in-out infinite alternate`;
|
||||||
|
// Random internal sway to prevent synchronized wiggling
|
||||||
|
rotationDiv.style.animationDelay = `-${Math.random() * 5}s`;
|
||||||
|
|
||||||
|
// Apply flip scale directly to the image inside rotationDiv
|
||||||
|
img.style.transform = `scale(${distanceScale}) ${directionScale}`;
|
||||||
|
rotationDiv.appendChild(img);
|
||||||
|
|
||||||
|
symbol.appendChild(rotationDiv);
|
||||||
|
|
||||||
|
symbol.style.top = `${Math.random() * 80 + 5}vh`;
|
||||||
|
symbol.style.animationDuration = `${durationSeconds}s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol.style.top = `${topPos}vh`;
|
|
||||||
symbol.style.animationDuration = `${durationSeconds}s`;
|
|
||||||
symbol.style.animationDelay = `${delaySeconds}s`;
|
|
||||||
|
|
||||||
// Small vertical sway
|
|
||||||
const swimSway = document.createElement('div');
|
|
||||||
swimSway.style.animation = `underwater-sway ${Math.random() * 2 + 3}s ease-in-out infinite`;
|
|
||||||
swimSway.appendChild(symbol.cloneNode(true));
|
|
||||||
symbol.innerHTML = '';
|
|
||||||
symbol.appendChild(swimSway);
|
|
||||||
|
|
||||||
container.appendChild(symbol);
|
container.appendChild(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bubbles
|
// Start swimmer loops
|
||||||
|
spawnSwimmerLoop(fishImages, fishCount, fishSize, 'fish');
|
||||||
|
spawnSwimmerLoop(seahorsesImages, seahorseCount, seahorseSize, 'seahorse');
|
||||||
|
spawnSwimmerLoop(jellyfishImages, jellyfishCount, jellyfishSize, 'jellyfish');
|
||||||
|
spawnSwimmerLoop(turtleImages, turtleCount, turtleSize, 'turtle');
|
||||||
const bubbleCount = isMobile ? 15 : 30;
|
const bubbleCount = isMobile ? 15 : 30;
|
||||||
|
|
||||||
for (let i = 0; i < bubbleCount; i++) {
|
for (let i = 0; i < bubbleCount; i++) {
|
||||||
@@ -163,13 +353,7 @@ function createUnderwater() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUnderwaterEmojiFallback(type) {
|
|
||||||
if (type === 'fish_orange') return '🐠';
|
|
||||||
if (type === 'fish_blue') return '🐟';
|
|
||||||
if (type === 'jellyfish') return '🪼';
|
|
||||||
if (type === 'turtle') return '🐢';
|
|
||||||
return '🫧';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeUnderwater() {
|
function initializeUnderwater() {
|
||||||
if (!underwater) return;
|
if (!underwater) return;
|
||||||
|
|||||||
@@ -8,9 +8,17 @@
|
|||||||
"category": "General",
|
"category": "General",
|
||||||
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/logo.png",
|
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/logo.png",
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "2.0.0.8",
|
||||||
|
"changelog": "feat: add new themes:\n- birthday (ballons, computer mouse interactive)\n- earthday\n- Eid al-Fitr (sugar feast/ramadan)\n- eurovision\n- Film Noir filter\n- Friday the 13\n- frost\n- Mario Day\n- Matrix\n- Oktoberfest\n- Olympia\n- Oscar Awards\n- Pride\n- Rain\n- Spooky\n- Sports (many selectable balls of ball games like handball, football (soccer) or tennis)\n- StarWars Day\n- Storm (Epilepsy Warning!!!, Thunderstorm)\n\n- refactored spring (new lawn with flowers), easter (new easter bunny, new lawn with flowers and ester eggs), halloween (add spiders (computer mouse sensitive), add mice, add fog) \n- fix: many improvements and bug fixes e.g. changed top to translate/transform for performance reasons",
|
||||||
|
"targetAbi": "10.11.0.0",
|
||||||
|
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v2.0.0.8/Jellyfin.Plugin.Seasonals.zip",
|
||||||
|
"checksum": "da10c4e44858f796cae1b77d0b866480",
|
||||||
|
"timestamp": "2026-02-28T15:28:11Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.7.2.0",
|
"version": "1.7.2.0",
|
||||||
"changelog": "- feat: add Pi Day, Pride, Rain, and Storm themes\n- fix: improve performance",
|
"changelog": "- feat: add Pi Day, Pride, Rain, and Storm themes\n- fix: improve performance",
|
||||||
"targetAbi": "10.11.0.0",
|
"targetAbi": "10.11.0.0",
|
||||||
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v1.7.2.0/Jellyfin.Plugin.Seasonals.zip",
|
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v1.7.2.0/Jellyfin.Plugin.Seasonals.zip",
|
||||||
"checksum": "34c8426c48bd7d470c3e8dc7f02f86da",
|
"checksum": "34c8426c48bd7d470c3e8dc7f02f86da",
|
||||||
|
|||||||