├── .github
└── workflows
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── client.lua
├── fxmanifest.lua
└── web
├── assets
├── markdown_parser.js
├── music.js
├── script.js
├── styles.css
└── utils.js
├── backgrounds
├── 1.jpg
├── 2.jpg
├── 3.jpg
└── 4.jpg
├── config.js
├── index.html
├── logo
└── logo.png
└── music
└── music.mp3
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release Publisher
2 | on:
3 | push:
4 | tags:
5 | - "*"
6 | jobs:
7 | release:
8 | name: Tagged Release
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v2
13 | with:
14 | fetch-depth: 0
15 | ref: ${{ github.ref }}
16 |
17 | - name: Get Version Tag
18 | id: get_version_tag
19 | run: echo ::set-output name=VERSION_TAG::${GITHUB_REF/refs\/tags\//}
20 |
21 | - name: Create Release File
22 | run: |
23 | mkdir -p ./temp/pe-basicloading
24 | cp -r ./{LICENSE,README.md,client.lua,fxmanifest.lua,web} ./temp/pe-basicloading
25 | cd ./temp && zip -r pe-basicloading-${{ steps.get_version_tag.outputs.VERSION_TAG }}.zip ./pe-basicloading
26 |
27 | - name: Create and Upload Release
28 | uses: marvinpinto/action-automatic-releases@v1.2.1
29 | with:
30 | repo_token: ${{ secrets.GITHUB_TOKEN }}
31 | prerelease: false
32 | files: ./temp/pe-basicloading-${{ steps.get_version_tag.outputs.VERSION_TAG }}.zip
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Project Error
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
19 | OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Project Error Basic Loading
5 |
6 |
7 | A very basic, yet still robust and extendable, loading screen.
8 |
9 |
10 |
11 |
12 | [](https://github.com/project-error/pe-basicloading/master/LICENSE)
13 | 
14 |
15 |
16 |
17 |
18 | You can find a short preview video [here](https://i.imgur.com/aivxpfx.gifv)
19 |
20 |
21 | ## Features
22 | * Customizable tip section that can be switched through
23 | * Markdown support for tip section content. Also allows for navigation using the **Left** and **Right** arrow keys
24 | * Customizable animated backgrounds that smoothly transition
25 | * CSS/JS cursor implementation, allowing for its use while loading
26 | * Special markdown link parsing allowing for users to click on markdown links that will open in the user's default browser
27 |
28 | ## Quick Start
29 | 1. Download the latest release from [here](https://github.com/project-error/pe-basicloading/releases/)
30 | 2. Unzip and drag the `pe-basicloading` folder into your `resources` directory
31 | 3. Add `ensure pe-basicloading` to your `server.cfg`
32 |
33 | *Note: This resource uses the `MANUAL_SHUTDOWN` feature. You can learn more about that [here](https://docs.fivem.net/natives/?_0x1722C938)*
34 |
35 | ## Config Options
36 |
37 | The config can be found in `web/config.js`. This holds a plethora of configuration options.
38 |
39 | | Option | Description | Example
40 | | --- | --- | --- |
41 | | LOADSCREEN_TIPS | An array of `TipObjects` for displaying in the loading screen | [Here](https://github.com/project-error/pe-basicloading/blob/db5837df618a9d9fd6a4cd2a218bb91e81a359b7/web/config.js#L7)|
42 | | TIP_CHANGE_INTERVAL | The interval (ms) at which Tips change automatically | `TIP_CHANGE_INTERVAL = 12000` |
43 | | BACKGROUND_CHANGE_INTERVAL | The interval (ms) at which backgrounds automatically switch | `BACKGROUND_CHANGE_INTERVAL = 15000` |
44 | | BACKGROUND_IMAGES | An array of file names for images present in the `web/backgrounds` folder. | `BACKGROUND_IMAGES = ["1.jpg","2.jpg"]`
45 | | ENABLE_GFM_MARKDOWN | Whether to enable the `Github Flavored Markdown` spec for the parser | `ENABLE_GFM_MARKDOWN = true`
46 | | ENABLE_SERVER_LOGO | Whether to enable the server logo | `ENABLE_SERVER_LOGO = true`
47 | | SERVER_LOGO_POSITION | Where to place logo if enabled | `SERVER_LOGO_POSITION = 'top-left'`
48 | | SERVER_LOGO_FILE_NAME | The name of your logo file within "logo/" directory | `SERVER_LOGO_FILE_NAME = 'logo.png'`
49 | | MUSIC_ENABLED | Enable loading music | `MUSIC_ENABLED = true `
50 | | MUSIC_START_VOLUME | The volume for loading music (0 - 1.0) | `MUSIC_START_VOLUME = 0.5`
51 | | MUSIC_FILE_NAME | The name of the music file to play in the "music/" folder | `MUSIC_FILE_NAME = 'music.mp3'`
52 |
53 | ## Customize
54 |
55 | ### Adding Backgrounds
56 |
57 | Adding or replacing images is very simple.
58 |
59 | 1. First ensure that the image is in the `web/backgrounds` folder.
60 | 2. Then open the `web/config.js` file and add the exact filename for your image
61 | to the `BACKGROUND_IMAGES` array.
62 |
63 | 📁 **web/config.js**
64 | ```js
65 | // An array of image files that are available in the `bg` folder
66 | export const BACKGROUND_IMAGES = [
67 | "1.jpg",
68 | "2.jpg",
69 | "3.jpg",
70 | "4.jpg",
71 | "5.jpg",
72 | "6.jpg",
73 | "7.jpg",
74 | "8.jpg",
75 | "YourNewImage.jpg"
76 | ]
77 | ```
78 |
79 | ### Adding Tips
80 | This loadscreen employs dynamic tooltips as one of its main features. These are
81 | defined in the `web/config.js` file under the `LOADSCREEN_TIPS` array.
82 |
83 | The data structure of tooltips are fairly simple, they are defined with a `title`
84 | and a `content` property. Here's a simple example.
85 |
86 | ```
87 | {
88 | title: 'My Tooltip Title',
89 | content: 'This is the markdown compatible content that will be shown on screen'
90 | }
91 | ```
92 |
93 | **Markdown Compatible Content**
94 |
95 | An important thing to note with **Tips** is that the content property is **markdown compatible**.
96 | Meaning you can employ the same syntax that you might be comfortable with while for example using Discord.
97 |
98 | **Structure in Config**
99 | ```
100 | {
101 | title: 'Markdown Render',
102 | content: '**This is bold**. But this is not. [This is a link!](https://github.com/project-error/pe-basicloading/#)'
103 | }
104 | ```
105 | **Rendered Output**
106 | 
107 |
108 | The markdown parser utilized is fully compliant with the original `Markdown.pl` spec and around 60% compliant
109 | with `CommonMarkdown` spec. `Github Flavored Markdown` can also be enabled in the `config.js`.
110 |
111 | ## Script Integration
112 |
113 | This loading screen can be implemented directly into scripts easily. As a standalone script, it will wait
114 | for the `spawnPlayer` event to be triggered by spawnmanager before shutting down. If you wish to control its
115 | behavior directly, use the following convars and exports
116 |
117 | **Convars**
118 |
119 | `pe-basicloading:disableAutoShutdown`
120 | * Description: Controls whether script should auto shutdown loading on `playerSpawned` event
121 | * Usage: `set pe-basicloading:disableAutoShutdown 1`
122 |
123 | **Exports**
124 |
125 | `shutdown`
126 | * Description: Will shutdown the loading frame and cleanup.
127 | * Usage: `exports["pe-basicloading"]:shutdown()`
128 |
129 | ## License
130 | [Licensed under MIT](https://opensource.org/licenses/MIT)
131 |
--------------------------------------------------------------------------------
/client.lua:
--------------------------------------------------------------------------------
1 | local disableManualShutdown = GetConvarInt('pe-basicloading:disableAutoShutdown', 0) == 1
2 |
3 | local function shutdownHandler()
4 | CreateThread(function()
5 | SendLoadingScreenMessage(json.encode({
6 | fullyLoaded = true
7 | }))
8 | Wait(5000)
9 | ShutdownLoadingScreenNui(true)
10 | end)
11 | end
12 |
13 | if not disableManualShutdown then
14 | AddEventHandler('playerSpawned', shutdownHandler)
15 | end
16 |
17 | exports('shutdown', shutdownHandler)
--------------------------------------------------------------------------------
/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 | game 'gta5'
3 |
4 | author 'Project Error'
5 | description 'A basic yet robust and extendable loading screen'
6 | version '1.2.0'
7 | repository 'https://github.com/project-error/pe-basicloading'
8 |
9 | loadscreen 'web/index.html'
10 |
11 | client_script 'client.lua'
12 |
13 | loadscreen_cursor 'yes'
14 |
15 | loadscreen_manual_shutdown 'yes'
16 |
17 | files {
18 | "config.json",
19 | "web/**/*"
20 | }
--------------------------------------------------------------------------------
/web/assets/markdown_parser.js:
--------------------------------------------------------------------------------
1 | import { ENABLE_GFM_MARKDOWN, LOADSCREEN_TIPS } from "../config.js";
2 | import { cleanUrl } from "./utils.js";
3 |
4 | window.__openUrl = (url) => window.invokeNative ? window.invokeNative('openUrl', url) : window.open(url)
5 |
6 | const renderer = {
7 | link(href, title, text) {
8 | href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
9 | if (href === null) {
10 | return text;
11 | }
12 | // let out = `${text} `;
20 | return out;
21 | }
22 | }
23 |
24 | marked.use({ renderer })
25 |
26 | marked.setOptions({
27 | gfm: ENABLE_GFM_MARKDOWN
28 | })
29 |
30 | export const parsedMdTips = LOADSCREEN_TIPS.map(({title, content}) => {
31 | const rendered = window.marked.parse(content)
32 | return {title, content: rendered}
33 | })
34 |
--------------------------------------------------------------------------------
/web/assets/music.js:
--------------------------------------------------------------------------------
1 | import {
2 | MUSIC_ENABLED,
3 | MUSIC_FILE_NAME,
4 | MUSIC_START_VOLUME,
5 | SERVER_LOGO_POSITION,
6 | ENABLE_SERVER_LOGO
7 | } from "../config.js";
8 |
9 | const music = document.getElementById("loadscreen-music");
10 | const musicControls = document.getElementById("audio-controls")
11 | const validLocations = ['top-left', "top-right", 'bottom-right']
12 |
13 | // Make sure we don't overlap with the logo option
14 | const determineMusicLocation = () => {
15 | if (!ENABLE_SERVER_LOGO) {
16 | musicControls.classList.add('top-left')
17 | } else {
18 |
19 | for (const location of validLocations) {
20 | if (SERVER_LOGO_POSITION === location) continue;
21 | musicControls.classList.add(location)
22 | break;
23 | }
24 | }
25 | }
26 |
27 | // Will toggle location logic and opacity
28 | const showMusicControls = () => {
29 | determineMusicLocation()
30 | musicControls.style.opacity = '100';
31 | }
32 |
33 | // Basic function for starting music
34 | export const startMusic = () => {
35 | if (!MUSIC_ENABLED) return;
36 |
37 | showMusicControls();
38 |
39 | // Setup music volume
40 | music.src = `music/${MUSIC_FILE_NAME}`;
41 | music.volume = MUSIC_START_VOLUME;
42 |
43 | document.addEventListener('keypress', (event) => {
44 | switch (event.key) {
45 | case 'p':
46 | if (music.paused) music.play();
47 | else music.pause();
48 | break;
49 | case 'w': {
50 | const wantedNewVol = music.volume + 0.05
51 | if (wantedNewVol > 1) return;
52 | music.volume = wantedNewVol;
53 | break;
54 | }
55 | case 's': {
56 | const wantedNewVol = music.volume - 0.05;
57 | if (wantedNewVol < 0) return;
58 | music.volume = wantedNewVol
59 | break;
60 | }
61 | }
62 | });
63 | }
64 |
65 | export const stopMusic = () => {
66 | if (!music.paused) music.pause()
67 | musicControls.opacity = '0'
68 | }
--------------------------------------------------------------------------------
/web/assets/script.js:
--------------------------------------------------------------------------------
1 | import {
2 | TIP_CHANGE_INTERVAL,
3 | BACKGROUND_CHANGE_INTERVAL,
4 | BACKGROUND_IMAGES,
5 | SERVER_LOGO_POSITION,
6 | ENABLE_SERVER_LOGO,
7 | MUSIC_ENABLED, SERVER_LOGO_FILE_NAME
8 | } from '../config.js'
9 |
10 | import { parsedMdTips } from "./markdown_parser.js";
11 | import { startMusic, stopMusic } from "./music.js";
12 |
13 | /**
14 | * @typedef {Object} TooltipObject
15 | * @property {string} title - The title of the tooltip
16 | * @property {string} content - The HTML contents
17 | **/
18 |
19 | const headerEl = $('#tip-header')
20 | const contentEl = $('#tip-content')
21 | const hintHelpTxtEl = $('#hint-help-text')
22 | const containerEL = $('#page-wrapper')
23 | const bgImgEl = $('#bgImg')
24 | const spinnerEl = $('#spinner')
25 | const logoEl = $('#server-logo')
26 |
27 |
28 | // We store the current tipInterval if any here
29 | let tipInterval = null
30 |
31 | // We store the current tipIndex here
32 | let currentTipIndex
33 |
34 | /**
35 | * Set the current tooltip
36 | * @param tooltipObj {TooltipObject} - The tooltip object
37 | * @param index {number} - The array index for this particular tooltip object
38 | **/
39 | const setCurrentTip = ({title, content}, index) => {
40 | headerEl.fadeOut("fast", () => {
41 | headerEl.html(title)
42 | headerEl.fadeIn("fast")
43 | })
44 | contentEl.fadeOut("fast", () => {
45 | contentEl.html(content)
46 | contentEl.fadeIn("fast")
47 | })
48 | hintHelpTxtEl.text(`Browse Tips ${index + 1}/${parsedMdTips.length}`)
49 | currentTipIndex = index
50 |
51 | if (tipInterval) {
52 | clearInterval(tipInterval)
53 | }
54 |
55 | tipInterval = setInterval(() => showNextTip(), TIP_CHANGE_INTERVAL)
56 | }
57 |
58 | /**
59 | * Handle the left arrow "prev" tooltip
60 | **/
61 | const showPrevTip = () => {
62 | const prevTipIdx = currentTipIndex - 1
63 | const finalTipIdx = parsedMdTips.length - 1
64 |
65 | clearInterval(tipInterval)
66 |
67 | if (prevTipIdx < 0) {
68 | const tipObj = parsedMdTips[finalTipIdx]
69 | setCurrentTip(tipObj, finalTipIdx)
70 | } else {
71 | const tipObj = parsedMdTips[prevTipIdx]
72 | setCurrentTip(tipObj, prevTipIdx)
73 | }
74 | }
75 |
76 | /**
77 | * Handle the right arrow "next" tooltip
78 | **/
79 | const showNextTip = () => {
80 | const nextTipIdx = currentTipIndex + 1
81 |
82 | if (nextTipIdx > parsedMdTips.length - 1) {
83 | const tipObj = parsedMdTips[0]
84 | setCurrentTip(tipObj, 0)
85 | } else {
86 | const tipObj = parsedMdTips[nextTipIdx]
87 | setCurrentTip(tipObj, nextTipIdx)
88 | }
89 | }
90 |
91 | /**
92 | * Find random tooltip and set it as current
93 | **/
94 | const setRandomTip = () => {
95 | const randomTipIndex = Math.floor(Math.random() * parsedMdTips.length)
96 | const randomTipObj = parsedMdTips[randomTipIndex]
97 | setCurrentTip(randomTipObj, randomTipIndex)
98 | }
99 |
100 | /**
101 | * Shutdowns and cleanups loading frame
102 | **/
103 | const cleanupLoadingScreen = () => {
104 | containerEL.fadeOut('slow')
105 | if (MUSIC_ENABLED) stopMusic();
106 | }
107 |
108 | let currentBgIdx = 0
109 |
110 | /**
111 | * Start the interval for background changes
112 | **/
113 | const startBackgroundInterval = () => {
114 | setInterval(() => {
115 |
116 | const nextImgIdx = currentBgIdx + 1
117 | const imgIdx = (nextImgIdx > BACKGROUND_IMAGES.length - 1) ? 0 : nextImgIdx
118 |
119 | const bgFileName = BACKGROUND_IMAGES[imgIdx]
120 |
121 | bgImgEl.css("background-image", `url(backgrounds/${bgFileName})`)
122 |
123 | currentBgIdx = imgIdx
124 | }, BACKGROUND_CHANGE_INTERVAL)
125 | }
126 |
127 | /*
128 | Set Initial element class for server logo placement
129 | */
130 | const setupServerLogo = () => {
131 | if (!ENABLE_SERVER_LOGO) return;
132 | const logoLocation = `./logo/${SERVER_LOGO_FILE_NAME}`
133 | logoEl.css('background', `url(${logoLocation})`)
134 | logoEl.css('background-size', 'contain')
135 | logoEl.css('visibility', 'visible')
136 | logoEl.addClass(SERVER_LOGO_POSITION)
137 | }
138 |
139 | /* Listeners */
140 |
141 | window.addEventListener('DOMContentLoaded', () => {
142 | startBackgroundInterval()
143 | setRandomTip()
144 | setupServerLogo()
145 | spinnerEl.fadeIn()
146 | startMusic()
147 | })
148 |
149 | window.addEventListener('keydown', (e) => {
150 | if (e.code === 'ArrowLeft') {
151 | showPrevTip()
152 | } else if (e.code === 'ArrowRight') {
153 | showNextTip()
154 | }
155 | })
156 |
157 | window.addEventListener('message', (e) => {
158 | // This is the shutdown message that is sent by client script
159 | if (e.data.fullyLoaded) {
160 | cleanupLoadingScreen()
161 | }
162 | })
163 |
164 | // Setup left and right click handlers
165 | const leftArrow = document.getElementById('tip-left-arrow')
166 | const rightArrow = document.getElementById('tip-right-arrow')
167 |
168 | leftArrow.addEventListener('click', showPrevTip)
169 | rightArrow.addEventListener('click', showNextTip)
--------------------------------------------------------------------------------
/web/assets/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
2 |
3 | body {
4 | height: 100vh;
5 | margin: 0;
6 | font-family: 'Roboto', sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | overflow: hidden;
10 | }
11 |
12 | a[onclick] {
13 | color: #4271ff;
14 | text-decoration: underline;
15 | }
16 |
17 | @keyframes spinner {
18 | from {
19 | transform: rotate(0deg);
20 | } to {
21 | transform: rotate(360deg);
22 | }
23 | }
24 |
25 | @keyframes breath {
26 | from {
27 | transform: scale(1);
28 | }
29 |
30 | to {
31 | transform: scale(1.5)
32 | }
33 | }
34 |
35 | .material-icons-outlined.md-primary { color: var(--primary-text)}
36 |
37 | .material-icons-outlined.md-light { color: var(--secondary-text) }
38 |
39 | .material-icons-outlined.md-18 { font-size: 18px; }
40 | .material-icons-outlined.md-24 { font-size: 24px; }
41 | .material-icons-outlined.md-26 { font-size: 26px; }
42 | .material-icons-outlined.md-36 { font-size: 36px; }
43 | .material-icons-outlined.md-48 { font-size: 48px; }
44 |
45 | :root {
46 | --primary-text: #fff;
47 | --secondary-text: #8F8F8F;
48 | --main-bg: rgba(0, 0, 0, 0.85)
49 | }
50 |
51 | #bgImg {
52 | background-image: url(../backgrounds/1.jpg);
53 | transition: background 1.5s linear;
54 | background-position: center;
55 | background-size: cover;
56 | background-repeat: no-repeat;
57 | animation: breath 15s ease-in-out alternate infinite;
58 | width: 110vw;
59 | height: 110vh;
60 | right: 0;
61 | bottom: 0;
62 | z-index: 1;
63 | position: absolute;
64 | }
65 |
66 | #server-logo {
67 | visibility: hidden;
68 | background-repeat: no-repeat;
69 | position: absolute;
70 | width: 15vh;
71 | height: 15vh;
72 | z-index: 2;
73 | }
74 |
75 | #audio-controls {
76 | height: 150px;
77 | width: 300px;
78 | z-index: 10;
79 | box-sizing: border-box;
80 | padding: 20px;
81 | color: var(--primary-text);
82 | position: absolute;
83 | opacity: 0;
84 | transition: opacity 0.5s ease-in-out;
85 | background: var(--main-bg);
86 | }
87 |
88 | #audio-controls > .header {
89 | font-size: 1.2rem;
90 | font-weight: 500;
91 | margin-bottom: 10px;
92 | }
93 |
94 | .audio-control-item {
95 | display: flex;
96 | align-items: center;
97 | }
98 |
99 | .audio-control-item > .control-text {
100 | margin-left: 5px;
101 | font-weight: normal;
102 | }
103 |
104 | .top-left {
105 | top: 3vh;
106 | left: 3vh;
107 | }
108 |
109 | .top-right {
110 | top: 3vh;
111 | right: 3vh;
112 | }
113 |
114 | .bottom-right {
115 | bottom: 3vh;
116 | top: 3vh;
117 | }
118 |
119 | #server-logo.center {
120 | top: 50%;
121 | transform: translateY(-50%);
122 | }
123 |
124 | .header-container {
125 | display: flex;
126 | justify-content: space-between;
127 | }
128 |
129 | .header-text {
130 | font-weight: bold;
131 | font-size: 25px;
132 | color: var(--primary-text);
133 | text-transform: uppercase;
134 | }
135 |
136 | .tip-text {
137 | font-weight: normal;
138 | font-size: 18px;
139 | color: var(--primary-text);
140 | flex-grow: 1;
141 | padding: 0;
142 | display: flex;
143 | align-items: center;
144 | }
145 |
146 | .hint-help-text {
147 | margin: 0 5px;
148 | font-weight: 400;
149 | font-size: 18px;
150 | color: var(--secondary-text);
151 | text-transform: uppercase;
152 | }
153 |
154 | .text-secondary {
155 | color: var(--secondary-text);
156 | }
157 |
158 | .hint-help-wrapper {
159 | display: flex;
160 | font-weight: normal;
161 | align-items: center;
162 | }
163 |
164 | #page-wrapper {
165 | height: 100%;
166 | width: 100%;
167 | display: flex;
168 | justify-content: center;
169 | align-items: flex-end;
170 | }
171 |
172 | .key {
173 | display: inline;
174 | font-family: monospace;
175 | font-weight: 800;
176 | margin: 0.25rem;
177 | padding: 0.1rem 0.35rem;
178 | color: #2C2C2C;
179 | background-color: var(--primary-text);
180 | border-radius: 4px;
181 | box-shadow: 1px 1px 0 2px #969696;
182 | }
183 |
184 | #tip-container {
185 | background: rgba(0, 0, 0, 0.85);
186 | display: flex;
187 | flex-direction: column;
188 | position: fixed;
189 | width: min(70vw, 1300px);
190 | height: 150px;
191 | padding: 20px;
192 | left: 3vh;
193 | margin-bottom: 3vh;
194 | transition: opacity linear .25s;
195 | z-index: 15;
196 | }
197 |
198 | #spinner {
199 | display: none;
200 | width: 20px;
201 | height: 20px;
202 | border: 5px solid rgba(255,255,255,.1);
203 | border-right: 5px solid orange;
204 | border-radius: 50%;
205 | animation: spinner 1s linear infinite;
206 | }
207 |
208 | .arrow-control {
209 | user-select: none;
210 | }
211 |
212 | .arrow-control:hover {
213 | cursor: pointer;
214 | }
215 |
216 |
--------------------------------------------------------------------------------
/web/assets/utils.js:
--------------------------------------------------------------------------------
1 | const nonWordAndColonTest = /[^\w:]/g;
2 | const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
3 |
4 | export function cleanUrl(sanitize, base, href) {
5 | if (sanitize) {
6 | let prot;
7 | try {
8 | prot = decodeURIComponent(unescape(href))
9 | .replace(nonWordAndColonTest, '')
10 | .toLowerCase();
11 | } catch (e) {
12 | return null;
13 | }
14 | if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
15 | return null;
16 | }
17 | }
18 | if (base && !originIndependentUrl.test(href)) {
19 | href = resolveUrl(base, href);
20 | }
21 | try {
22 | href = encodeURI(href).replace(/%25/g, '%');
23 | } catch (e) {
24 | return null;
25 | }
26 | return href;
27 | }
28 |
29 | export const getCurrentScriptsName = () => window.GetParentResourceName ? GetParentResourceName() : ''
--------------------------------------------------------------------------------
/web/backgrounds/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/backgrounds/1.jpg
--------------------------------------------------------------------------------
/web/backgrounds/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/backgrounds/2.jpg
--------------------------------------------------------------------------------
/web/backgrounds/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/backgrounds/3.jpg
--------------------------------------------------------------------------------
/web/backgrounds/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/backgrounds/4.jpg
--------------------------------------------------------------------------------
/web/config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This is where you want to add your tips. They **MUST** be in this structure. You can
3 | * have as many or little as you want. In each tooltip object, the `content` value also supports markdown
4 | *
5 | * A list of the markdown supported can be found on the docs
6 | */
7 | export const LOADSCREEN_TIPS = [
8 | {
9 | title: "Bold Tip",
10 | content: "**This is just a bold tip. WOW its all bold!**"
11 | },
12 | {
13 | title: "Italics Tip",
14 | content: "*Wew, now its all in italics*"
15 | },
16 | {
17 | title: "Bold Italics",
18 | content: "***Lets now combine the best of both worlds! Lets use bold italics***"
19 | },
20 | {
21 | title: "Nice Tip 4",
22 | content: "Find our discord here"
23 | },
24 | {
25 | title: 'Markdown Render',
26 | content: '**This is bold**. But this is not. [This is a link!](https://github.com/project-error/pe-basicloading)'
27 | }
28 | ];
29 |
30 | // How long a tip is on screen before we aut omatically
31 | // go to the next one (ms)
32 | export const TIP_CHANGE_INTERVAL = 10000
33 |
34 | // How long we stay on a background until we
35 | // go to the next one (ms)
36 | export const BACKGROUND_CHANGE_INTERVAL = 5000
37 |
38 | // An array of image files that are available in the `bg` folder
39 | export const BACKGROUND_IMAGES = [
40 | "1.jpg",
41 | "2.jpg",
42 | "3.jpg",
43 | "4.jpg",
44 | ]
45 |
46 | // Whether music should be played while loading,
47 | // this will automatically loop the file as well
48 | export const MUSIC_ENABLED = true
49 |
50 | // The file name given to your music. This can be
51 | // a .ogg or an .mp3 (MUST BE PRESENT IN `music/` folder)
52 | export const MUSIC_FILE_NAME = 'music.mp3'
53 |
54 | export const MUSIC_START_VOLUME = 0.3
55 |
56 | // Enable github flavored markdown
57 | export const ENABLE_GFM_MARKDOWN = false
58 |
59 | // Enable or disable the included server logo to change this
60 | // logo simply switch the `logo.png` file with the image of your choice
61 | export const ENABLE_SERVER_LOGO = true
62 |
63 | // Define server logo placement ['top-left', 'top-right', 'bottom-right', 'center']
64 | export const SERVER_LOGO_POSITION = 'center'
65 |
66 | // The name of your logo file within "logo/" directory
67 | export const SERVER_LOGO_FILE_NAME = 'logo.png'
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | PE-LOADING-SCREEN
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | volume_up
27 |
28 |
29 | [W] - Volume Up
30 |
31 |
32 |
33 |
34 | volume_down
35 |
36 |
37 | [S] - Volume Down
38 |
39 |
40 |
41 |
42 | pause
43 |
44 |
45 |
46 | [P] - Play/Pause
47 |
48 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 | chevron_left
63 |
64 |
65 |
66 | chevron_right
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/web/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/logo/logo.png
--------------------------------------------------------------------------------
/web/music/music.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/project-error/pe-basicloading/a6a8e1862304e7de6b0d718190fd4992da71c478/web/music/music.mp3
--------------------------------------------------------------------------------