├── .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 | Material-UI logo

3 |

4 |

Project Error Basic Loading

5 | 6 |
7 | A very basic, yet still robust and extendable, loading screen. 8 |
9 | 10 |
11 | 12 | [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/project-error/pe-basicloading/master/LICENSE) 13 | ![Discord](https://img.shields.io/discord/791854454760013827?label=Our%20Discord) 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 | ![img](https://i.tasoagc.dev/SB6A) 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 | 19 |
20 |
21 | 22 |
23 |
Music Control
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 |
54 |
55 |
56 |
57 |
58 |
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 --------------------------------------------------------------------------------