diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2481fa5c2..12a9e03a6 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,8 @@ # These are supported funding model platforms open_collective: haxe -custom: ['https://haxe.org/foundation/support-plans.html', 'https://haxe.org/foundation/donate.html'] +custom: + [ + "https://haxe.org/foundation/support-plans.html", + "https://haxe.org/foundation/donate.html", + ] diff --git a/.github/PULL_REQUEST_TEMPLATE/addition.yml b/.github/PULL_REQUEST_TEMPLATE/addition.yml index 7ab6d2912..97bb6a2e9 100644 --- a/.github/PULL_REQUEST_TEMPLATE/addition.yml +++ b/.github/PULL_REQUEST_TEMPLATE/addition.yml @@ -16,4 +16,4 @@ body: - type: textarea attributes: label: Screenshots/Videos - placeholder: Demonstrate your additions here... \ No newline at end of file + placeholder: Demonstrate your additions here... diff --git a/.github/PULL_REQUEST_TEMPLATE/enhancement.yml b/.github/PULL_REQUEST_TEMPLATE/enhancement.yml index cebe89c91..b048634b1 100644 --- a/.github/PULL_REQUEST_TEMPLATE/enhancement.yml +++ b/.github/PULL_REQUEST_TEMPLATE/enhancement.yml @@ -16,4 +16,4 @@ body: - type: textarea attributes: label: Screenshots/Videos - placeholder: Demonstrate your enhancements here... \ No newline at end of file + placeholder: Demonstrate your enhancements here... diff --git a/.github/PULL_REQUEST_TEMPLATE/fix.yml b/.github/PULL_REQUEST_TEMPLATE/fix.yml index d58173591..8742c33f8 100644 --- a/.github/PULL_REQUEST_TEMPLATE/fix.yml +++ b/.github/PULL_REQUEST_TEMPLATE/fix.yml @@ -16,4 +16,4 @@ body: - type: textarea attributes: label: Screenshots/Videos - placeholder: Demonstrate your fixes here... \ No newline at end of file + placeholder: Demonstrate your fixes here... diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2021827c8..461c0c63b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,51 +2,51 @@ name: Build and Test on: push: - branches: [ main, master ] + branches: [main, master] pull_request: - branches: [ main, master ] + branches: [main, master] jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - with: + - name: Checkout code + uses: actions/checkout@v4 + with: submodules: true # we need full git history for article dates fetch-depth: 0 - - - name: Setup Haxe - uses: krdlab/setup-haxe@v1 - with: - haxe-version: 4.3.5 - - - name: Install Node.js and npm - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install - # at some point all npm needs to be in package.json - run: | - npm install - npm install -g less@2.7 - npm install -g less-plugin-clean-css@1.5 - haxelib install CodeCookBook-neko.hxml --always --quiet - haxelib install highlighting.hxml --always --quiet - haxelib list - - - name: Run build script - run: haxe build.hxml - - - name: Upload build artifacts (optional) - uses: actions/upload-artifact@v4 - with: - name: build-output - path: | - output/ - output/ - if-no-files-found: ignore + + - name: Setup Haxe + uses: krdlab/setup-haxe@v1 + with: + haxe-version: 4.3.5 + + - name: Install Node.js and npm + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "npm" + + - name: Install + # at some point all npm needs to be in package.json + run: | + npm install + npm install -g less@2.7 + npm install -g less-plugin-clean-css@1.5 + haxelib install CodeCookBook-neko.hxml --always --quiet + haxelib install highlighting.hxml --always --quiet + haxelib list + + - name: Run build script + run: haxe build.hxml + + - name: Upload build artifacts (optional) + uses: actions/upload-artifact@v4 + with: + name: build-output + path: | + output/ + output/ + if-no-files-found: ignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..e78e68a3a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +**/*.min.* +.haxelib/ +grammars/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/.vscode/settings.json b/.vscode/settings.json index a0c1d607e..e62a34497 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ -{"files.associations": { - "*.mtt": "html" - } -} \ No newline at end of file +{ + "files.associations": { + "*.mtt": "html" + } +} diff --git a/README.md b/README.md index 16a930673..0bb35ac13 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Funkin' Code CookBook + ## [**READ THE DOCUMENTATION HERE**](https://thekade.net/funkin-cookbook/) + > The link above is a **TEMPORARY** link, and **WILL BE CHANGED** in the future! Forked from [Haxe Code CookBook](https://github.com/HaxeFoundation/code-cookbook), this is a one stop shop for all Funkin' Modding Tutorials! @@ -15,11 +17,14 @@ You need [Haxe 3.4.2+](https://haxe.org/download/list/) installed. The static site generator source depends on [hxtemplo](https://lib.haxe.org/p/hxtemplo) and [haxe-markdown (funkin crew fork!)](https://github.com/FunkinCrew/haxe-markdown). Install the libraries using haxelib, run the following command in the root of the project: + ``` haxelib install all ``` -The CSS files are compressed using [less](http://lesscss.org/#using-less). + +The CSS files are compressed using [less](http://lesscss.org/#using-less). Install from npm: + ``` npm install ``` diff --git a/assets/content/cookbook/Advanced/01.HScript.md b/assets/content/cookbook/Advanced/01.HScript.md index ff530477e..19330bdc0 100644 --- a/assets/content/cookbook/Advanced/01.HScript.md +++ b/assets/content/cookbook/Advanced/01.HScript.md @@ -73,4 +73,4 @@ As you can see, you can basically use HScript like regular haxe, making it ideal [^philly]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Advanced/02.ScriptedClasses.md b/assets/content/cookbook/Advanced/02.ScriptedClasses.md index bfb3936f2..6305f515f 100644 --- a/assets/content/cookbook/Advanced/02.ScriptedClasses.md +++ b/assets/content/cookbook/Advanced/02.ScriptedClasses.md @@ -25,16 +25,15 @@ class BallisticSong extends Song { There is a predefined list of classes which the game has set up to be scriptable, and will automatically load and execute when relevant. More of these will be added in the future. - `funkin.play.song.Song` for providing unique behavior to custom songs, including playing cutscenes and other stuff. See [Scripted Songs](03.ScriptedSongs.md). - - See also [Video Cutscenes](09.VideoCutscenes.md), [Ingame Cutscenes](21-scripted-classes/21-04-ingame-cutscenes.md), and [Dialogue Cutscenes](08.DialogueCutscenes.md) + - See also [Video Cutscenes](09.VideoCutscenes.md), [Ingame Cutscenes](21-scripted-classes/21-04-ingame-cutscenes.md), and [Dialogue Cutscenes](08.DialogueCutscenes.md) - `funkin.play.character.BaseCharacter` for providing unique behavior to custom characters (such as playing custom animations in certain circumstances). See [Scripted Characters](04.ScriptedCharacters.md). + - Note that you need to choose the correct subclass of this class for the animation type of your character! + - `funkin.play.character.SparrowCharacter` is used for characters that have Sparrow spritesheet animations. + - `funkin.play.character.MultiSparrowCharacter` is used for characters that have several Sparrow spritesheet animations to combine into one character. + - `funkin.play.character.PackerCharacter` is used for characters that have Packer spritesheet animations. + - `funkin.play.character.AnimateAtlasCharacter` is used for characters that have Adobe Animate texture atlases. + - `funkin.play.character.BaseCharacter` has empty stubs for all the rendering and animation handlers, and is only useful for people who want to reimplement their character's animation system by hand. - - Note that you need to choose the correct subclass of this class for the animation type of your character! - - - `funkin.play.character.SparrowCharacter` is used for characters that have Sparrow spritesheet animations. - - `funkin.play.character.MultiSparrowCharacter` is used for characters that have several Sparrow spritesheet animations to combine into one character. - - `funkin.play.character.PackerCharacter` is used for characters that have Packer spritesheet animations. - - `funkin.play.character.AnimateAtlasCharacter` is used for characters that have Adobe Animate texture atlases. - - `funkin.play.character.BaseCharacter` has empty stubs for all the rendering and animation handlers, and is only useful for people who want to reimplement their character's animation system by hand. - `funkin.play.stage.Stage` for providing unique behavior to custom stages, such as creating custom moving props and defining when props animate or when sound effects play in sync with the stage. See [Scripted Stages](21-scripted-classes/24-06-scripted-stages.md). - `funkin.ui.story.Level` for providing unique behavior to levels in Story Mode. See [Scripted Story Levels](21-scripted-classes/25-07-scripted-story-levels.md). - `funkin.play.notes.notekind.NoteKind` for providing unique visuals and behavior to certain kinds of notes, which can then be placed in the Chart Editor. See [Custom Note Kinds](21-scripted-classes/26-00-custom-note-kinds.md). @@ -62,4 +61,4 @@ There are also scripted classes are also set up to be scriptable, but will only - `flixel.FlxState` for basic groups of sprites which represent a given game state. Use this only if you can't use MusicBeatState. - `flixel.FlxSubState` for groups of sprites representing a substate of an existing state -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Advanced/03.ScriptedSongs.md b/assets/content/cookbook/Advanced/03.ScriptedSongs.md index f91f4e1fb..20ec15778 100644 --- a/assets/content/cookbook/Advanced/03.ScriptedSongs.md +++ b/assets/content/cookbook/Advanced/03.ScriptedSongs.md @@ -1,4 +1,5 @@ [tags]: / "advanced,hscript,song" + # Scripted Songs This chapter will walk you through the process of adding a script to a Song, and giving examples of the kind of custom behavior which can be implemented with this functionality. @@ -27,6 +28,7 @@ You can then add override functions to perform custom behavior. ## Variation-Specific Song Scripts As of 0.7.4, if in the constructor you were to add an anonymous structure with the field `variation` as a parameter next to the song id, the song script will only be active for that variation. This prevents many conflicts with base game scripts and other mods that may add a variation, as the game would only call the functions from the variation-specific script. If a song doesn't have a variation-specific script, it will fallback to the default one, if it exists. An example of a variation-specific script can be found for Darnell Erect[^darnell] + ```haxe import funkin.play.song.Song; import funkin.save.Save; @@ -48,6 +50,7 @@ class DarnellErectSong extends Song ## Custom 'NEW'-Label criteria Usually, in the Freeplay menu, a song would not have the glowing 'NEW' label. However if you override the function `isSongNew`, you can have the label appear if a specific criteria is met. An example of this is found in the script for Cocoa (Pico Mix)[^cocoa] which returns true if the variation is Pico and the player hasn't beaten Cocoa Pico Mix. + ```haxe // ... @@ -65,6 +68,7 @@ public override function isSongNew(currentDifficulty:String, currentVariation:St ## Custom Alternate Instrumental behavior Instead of reading from the song's metadata file for possible alternate instrumentals, you can use scripts to lock some of them out of being used until a criteria is met. An example of this is found in the script for Stress[^stress] which locks the pico instrumental behind completing the pico remix, as well as not provide the default instrumental if the song is selected on the pico variation. + ```haxe // ... @@ -89,9 +93,10 @@ public override function listAltInstrumentalIds(difficultyId:String, variationId ## Hiding the Song from the Freeplay Menu The most important thing to override here is the function `listDifficulties`. If you return an empty array, the song will be omitted from the Freeplay menu. An example to this is in the song 2hot[^2hot] + ```haxe // ... - + // Line 51 public function listDifficulties(variationId:String, variationIds:Array, showLocked:Bool):Array { @@ -108,8 +113,11 @@ public function listDifficulties(variationId:String, variationIds:Array, ``` [^darnell]: + [^cocoa]: + [^stress]: + [^2hot]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Advanced/04.ScriptedCharacters.md b/assets/content/cookbook/Advanced/04.ScriptedCharacters.md index 1b5cc02ef..0e293d77e 100644 --- a/assets/content/cookbook/Advanced/04.ScriptedCharacters.md +++ b/assets/content/cookbook/Advanced/04.ScriptedCharacters.md @@ -1,4 +1,5 @@ [tags]: / "advanced,hscript,character" + # Scripted Characters This chapter will walk you through the process of adding a script to a Character, and giving examples of the kind of custom behavior which can be implemented with this functionality. @@ -143,8 +144,11 @@ override function getDeathQuote():Null ``` [^bf]: + [^nene]: + [^pico]: + [^bf-gf]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Advanced/05.ScriptedPlayableCharacters.md b/assets/content/cookbook/Advanced/05.ScriptedPlayableCharacters.md index 479ffc95a..35f73d3c1 100644 --- a/assets/content/cookbook/Advanced/05.ScriptedPlayableCharacters.md +++ b/assets/content/cookbook/Advanced/05.ScriptedPlayableCharacters.md @@ -1,4 +1,5 @@ [tags]: / "advanced,hscript,character" + # Scripted Playable Characters This chapter will walk you through the process of adding a script to a Playable Character, and giving examples of the kind of custom behavior which can be implemented with this functionality. @@ -37,4 +38,4 @@ The most important thing to override here is the `isUnlocked` function, which le } ``` -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Advanced/06.ScriptEventCallbacks.md b/assets/content/cookbook/Advanced/06.ScriptEventCallbacks.md index b08db8c82..c98fbfc99 100644 --- a/assets/content/cookbook/Advanced/06.ScriptEventCallbacks.md +++ b/assets/content/cookbook/Advanced/06.ScriptEventCallbacks.md @@ -11,223 +11,206 @@ Several base classes use functions that get an event dispatched to them whenever There is a predefined list of every script event callback the game has set up to be overridable, with their respective event type whose fields you can read from or write to. More of these will be added to the future. - `onScriptEvent(event:ScriptEvent)` - Called when any sort of script event would get dispatched. This is called before the event's respective callback. + - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - `onCreate(event:ScriptEvent)` - Called when the base class gets created in the game. + - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - `onDestroy(event:ScriptEvent)` - Called when the base class gets destroyed in the game. + - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - `onUpdate(event:UpdateScriptEvent)` - Called when the base class gets updated in the game. + - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - - Available to Songs, Stage Props, Boppers, Characters, Stages, Backing Cards, Note Kinds, Dialogue Boxes, Speakers, Conversations and Modules. - `onStateChangeBegin(event:StateChangeScriptEvent)` - Called when the State changing process begins. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onStateChangeEnd(event:StateChangeScriptEvent)` - Called when the State changing process ends. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onSubStateOpenBegin(event:SubStateScriptEvent)` - Called when the SubState opening process begins. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onSubStateOpenEnd(event:SubStateScriptEvent)` - Called when the SubState opening process ends. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onSubStateCloseBegin(event:SubStateScriptEvent)` - Called when the SubState closing process begins. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onSubStateCloseEnd(event:SubStateScriptEvent)` - Called when the SubState closing process ends. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onFocusLost(event:FocusScriptEvent)` - Called when the focus from the game window is lost. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onFocusGained(event:FocusScriptEvent)` - Called when the focus from the game window is gained. + - Available to Backing Cards and Modules. - - Available to Backing Cards and Modules. - `onAdd(event:ScriptEvent)` - Called when the base class is added to the game stage. + - Available to Stage Props, Boppers and Characters. - - Available to Stage Props, Boppers and Characters. - `onNoteIncoming(event:NoteScriptEvent)` - Called when a note is within the field of view. + - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - `onNoteHit(event:HitNoteScriptEvent)` - Called when a note is hit by either character. + - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. -- `onNoteMiss(event:NoteScriptEvent)` - Called when a note is missed by either character. +- `onNoteMiss(event:NoteScriptEvent)` - Called when a note is missed by either character. + - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - `onNoteHoldDrop(event:HoldNoteScriptEvent)` - Called when a hold note is dropped by either character. + - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - - Available to Songs, Boppers, Characters, Stages, Notekinds and Modules. - `onStepHit(event:SongTimeScriptEvent)` - Called when the Conductor reaches a new step of the music. + - Available to Songs, Boppers, Characters, Stages, Backing Cards and Modules. - - Available to Songs, Boppers, Characters, Stages, Backing Cards and Modules. -- `onBeatHit(event:SongTimeScriptEvent)` - Called when the Conductor reaches a new beat of the music. +- `onBeatHit(event:SongTimeScriptEvent)` - Called when the Conductor reaches a new beat of the music. + - Available to Songs, Boppers, Characters, Stages, Backing Cards and Modules. - - Available to Songs, Boppers, Characters, Stages, Backing Cards and Modules. - `onPause(event:PauseScriptEvent)` - Called when the main gameplay is paused. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onResume(event:ScriptEvent)` - Called when the main gameplay is resumed. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onSongLoaded(event:SongLoadScriptEvent)` - Called when song chart has been parsed but before the notes have been placed, both when starting the song for the first time and retrying the song. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onSongStart(event:ScriptEvent)` - Called when the song starts. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onSongEnd(event:ScriptEvent)` - Called when the song ends. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onGameOver(event:ScriptEvent)` - Called when the player runs out of health but before the game over substate is opened. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onSongRetry(event:SongRetryEvent)` - Called when the song retrying process begins, either through the pause menu or through the game over screen. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onNoteGhostMiss(event:GhostMissNoteScriptEvent)` - Called when the player pressed a key with no notes on the strumline. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onSongEvent(event:SongEventScriptEvent)` - Called when a song event (such as Focus Camera) is triggered. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onCountdownStart(event:CountdownScriptEvent)` - Called when the countdown is about to start. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onCountdownStep(event:CountdownScriptEvent)` - Called when a countdown changes its current step. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onCountdownEnd(event:CountdownScriptEvent)` - Called when the countdown ends. + - Available to Songs, Boppers, Characters, Stages and Modules. - - Available to Songs, Boppers, Characters, Stages and Modules. - `onDialogueCompleteLine(event:DialogueScriptEvent)` - Called when the player advanced the dialogue while it's being typed. + - Available to Dialogue Boxes, Speakers and Conversations. - - Available to Dialogue Boxes, Speakers and Conversations. - `onDialogueLine(event:DialogueScriptEvent)` - Called when the player advances the dialogue while it's idling. + - Available to Dialogue Boxes, Speakers and Conversations. - - Available to Dialogue Boxes, Speakers and Conversations. - `onDialogueSkip(event:DialogueScriptEvent)` - Called when the dialogue gets skipped. + - Available to Dialogue Boxes, Speakers and Conversations. - - Available to Dialogue Boxes, Speakers and Conversations. - `onDialogueEnd(event:DialogueScriptEvent)` - Called when the dialogue ends. - - - Available to Dialogue Boxes, Speakers and Conversations. + - Available to Dialogue Boxes, Speakers and Conversations. ## List of Event Types There is a predefined list of script events, whose fields are readable and, in some cases, changeable, that get dispatched to script event callbacks. More of these will be added in the future. See above which callback accepts which event. - `ScriptEvent`, with fields: - - - - (read-only) `cancelable` - If the event can be canceled. - - (read-only) `type` - The type of the event. - - (read-only) `shouldPropagate` - If the event can be dispatched to its respective callback. If false, it will only get dispatched to `onScriptEvent`. - - (read-only) `eventCanceled` - If the event has been cancelled. - - `cancelEvent()` - Cancels the event, if possible. - - `cancel()` - Cancels the event, if possible. - - `stopPropagation()` - Stops the propagation of this event. + - (read-only) `cancelable` - If the event can be canceled. + - (read-only) `type` - The type of the event. + - (read-only) `shouldPropagate` - If the event can be dispatched to its respective callback. If false, it will only get dispatched to `onScriptEvent`. + - (read-only) `eventCanceled` - If the event has been cancelled. + - `cancelEvent()` - Cancels the event, if possible. + - `cancel()` - Cancels the event, if possible. + - `stopPropagation()` - Stops the propagation of this event. - `UpdateScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `elapsed` - How much time has passed since the last update. + - Inherited from `ScriptEvent`. + - (read-only) `elapsed` - How much time has passed since the last update. - `StateChangeScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `targetState` - The State that was switched to. + - Inherited from `ScriptEvent`. + - (read-only) `targetState` - The State that was switched to. - `SubStateScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `targetState` - The SubState that was opened/closed. + - Inherited from `ScriptEvent`. + - (read-only) `targetState` - The SubState that was opened/closed. - `FocusScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. + - Inherited from `ScriptEvent`. - `NoteScriptEvent`, with fields: - - - Inherited from `ScriptEvent.` - - (read-only) `note` - The NoteSprite associated with this event. - - (read-only) `comboCount` - The currently ongoing combo. - - `playSound` - Whether to play a miss sound when missing a note. - - `healthChange` - The amount of health to add to the player. Can be a negative value too. + - Inherited from `ScriptEvent.` + - (read-only) `note` - The NoteSprite associated with this event. + - (read-only) `comboCount` - The currently ongoing combo. + - `playSound` - Whether to play a miss sound when missing a note. + - `healthChange` - The amount of health to add to the player. Can be a negative value too. - `HitNoteScriptEvent`, with fields: - - - Inherited from `NoteScriptEvent`. - - `judgement` - The judgement received from hitting the note. - - `score` - The score received from hitting the note. - - `isComboBreak` - If the hit caused a combo break. - - `hitDiff` - The time difference (in miliseconds) when the player hit the note. - - `doesNotesplash` - If the note does a splash, defaults to true when the judgement is "sick". + - Inherited from `NoteScriptEvent`. + - `judgement` - The judgement received from hitting the note. + - `score` - The score received from hitting the note. + - `isComboBreak` - If the hit caused a combo break. + - `hitDiff` - The time difference (in miliseconds) when the player hit the note. + - `doesNotesplash` - If the note does a splash, defaults to true when the judgement is "sick". - `HoldNoteScriptEvent`, with fields: - - - Inherited from `NoteScriptEvent`. - - `holdNote` - The SustainTrail object associated with this event. - - `score` - The score received from hitting the note. - - `isComboBreak` - If the hit caused a combo break. - - `hitDiff` - The time difference (in miliseconds) when the player hit the note. - - `doesNotesplash` - If the note does a splash, defaults to true when the judgement is "sick". + - Inherited from `NoteScriptEvent`. + - `holdNote` - The SustainTrail object associated with this event. + - `score` - The score received from hitting the note. + - `isComboBreak` - If the hit caused a combo break. + - `hitDiff` - The time difference (in miliseconds) when the player hit the note. + - `doesNotesplash` - If the note does a splash, defaults to true when the judgement is "sick". - `SongTimeScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `beat` - The current beat of the song. - - (read-only) `step` - The current step of the song. + - Inherited from `ScriptEvent`. + - (read-only) `beat` - The current beat of the song. + - (read-only) `step` - The current step of the song. - `PauseScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - `gitaroo` - If the Gitaroo Man easter egg should be used. + - Inherited from `ScriptEvent`. + - `gitaroo` - If the Gitaroo Man easter egg should be used. - `SongLoadScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `id` - The song id associated with the event. - - (read-only) `difficulty` - The song difficulty associated with the event. - - `notes` - An Array of SongNoteData objects representing the notes for the chart. - - `events` - An Array of SongEventData objects representing the events for the chart. + - Inherited from `ScriptEvent`. + - (read-only) `id` - The song id associated with the event. + - (read-only) `difficulty` - The song difficulty associated with the event. + - `notes` - An Array of SongNoteData objects representing the notes for the chart. + - `events` - An Array of SongEventData objects representing the events for the chart. - `SongRetryEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `difficulty` - The new difficulty of the song. + - Inherited from `ScriptEvent`. + - (read-only) `difficulty` - The new difficulty of the song. - `GhostMissNoteScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `dir` - The direction (1-4) that was mistakenly pressed. - - (read-only) `hasPossibleNotes` - If there were notes within judgement range when the key was pressed. - - `healthChange` - The amount of health to add to the player. Can be a negative value too. - - `scoreChange` - The amount of score to add to the player. Can be a negative value too. - - `playSound` - Whether to play a miss sound. - - `playAnim` - Whether to play a miss animation. + - Inherited from `ScriptEvent`. + - (read-only) `dir` - The direction (1-4) that was mistakenly pressed. + - (read-only) `hasPossibleNotes` - If there were notes within judgement range when the key was pressed. + - `healthChange` - The amount of health to add to the player. Can be a negative value too. + - `scoreChange` - The amount of score to add to the player. Can be a negative value too. + - `playSound` - Whether to play a miss sound. + - `playAnim` - Whether to play a miss animation. - `SongEventScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `eventData` - The SongEventData object associated with the event. + - Inherited from `ScriptEvent`. + - (read-only) `eventData` - The SongEventData object associated with the event. - `CountdownScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `step` - The current countdown step. Can be `BEFORE`, `THREE`, `TWO`, `ONE`, `GO` or `AFTER`. + - Inherited from `ScriptEvent`. + - (read-only) `step` - The current countdown step. Can be `BEFORE`, `THREE`, `TWO`, `ONE`, `GO` or `AFTER`. - `DialogueScriptEvent`, with fields: - - - Inherited from `ScriptEvent`. - - (read-only) `conversation` - The Conversation object associated with the event. + - Inherited from `ScriptEvent`. + - (read-only) `conversation` - The Conversation object associated with the event. ## Script Event Cancelling While most cannot be cancelled, cancelling some events provides more leeway to the custom behavior. An example to this would be having pre-song cutscenes, as seen in the script file for the song Darnell[^darnell] + ```haxe // ... @@ -260,13 +243,14 @@ public override function onCountdownStart(event:CountdownScriptEvent):Void ## Overriding Script Event Callbacks Even if most base classes have the script event callbacks as empty functions, others have behavior that is entirely dependant on them. As such, you can skip the behavior or call it under a condition depending on if and where you put your super function call. One such example is in the script file for Boyfriend (Christmas)[^bf-christmas] + ```haxe // ... function onNoteHit(event:HitNoteScriptEvent) { // ... - + // Override the hit note animation. switch (event.note.kind) { @@ -288,6 +272,7 @@ function onNoteHit(event:HitNoteScriptEvent) ``` [^darnell]: + [^bf-christmas]: > Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) diff --git a/assets/content/cookbook/Advanced/07.UsingTextFiles.md b/assets/content/cookbook/Advanced/07.UsingTextFiles.md index 596f11443..4dec281d1 100644 --- a/assets/content/cookbook/Advanced/07.UsingTextFiles.md +++ b/assets/content/cookbook/Advanced/07.UsingTextFiles.md @@ -2,7 +2,7 @@ # Text Files -While not used much by Friday Night Funkin' (in exception to `introText.txt`), the ability to read and save to text files may be useful for some mods. +While not used much by Friday Night Funkin' (in exception to `introText.txt`), the ability to read and save to text files may be useful for some mods. ## Reading a .txt file @@ -17,11 +17,11 @@ import funkin.play.song.Song; class Tutorial extends Song { var data:String = ''; // This variable will contain the text when we read the text file. - public function new() + public function new() { super("bopeebo"); // This is the song name, it must be lowercase here. } - + function onSongLoaded(event:ScriptEvent):Void { super.onSongLoaded(event); data = Assets.getText(Paths.txt("Player")); // Txt file, ALWAYS in "data" folder. @@ -44,15 +44,15 @@ import funkin.play.song.Song; import funkin.util.FileUtil; // Required module to save text files class Tutorial extends Song { - public function new() + public function new() { super("bopeebo"); // This must be the song name just lowercased } - + override public function onCreate():Void // This will be called upon the game starting { super.onCreate(); - FileUtil.writeStringToPath(Assets.getPath(Paths.txt("Player")), 'extra large potato'); + FileUtil.writeStringToPath(Assets.getPath(Paths.txt("Player")), 'extra large potato'); // Above will save to our mod's data folder to the text file named "Player.txt" and will write "extra large potato" in said text file } } @@ -67,11 +67,11 @@ import funkin.play.song.Song; import funkin.util.FileUtil; // Required module to save text files class Tutorial extends Song { - public function new() + public function new() { super("bopeebo"); // This must be the song name just lowercased } - + override public function onCreate():Void // This will be called upon the game starting { super.onCreate(); diff --git a/assets/content/cookbook/Advanced/08.DialogueCutscenes.md b/assets/content/cookbook/Advanced/08.DialogueCutscenes.md index 3376c85e1..ba45cd5f2 100644 --- a/assets/content/cookbook/Advanced/08.DialogueCutscenes.md +++ b/assets/content/cookbook/Advanced/08.DialogueCutscenes.md @@ -25,7 +25,7 @@ To start off you must make a few assets (or use the default ones). Let's go over "color": "#3F2021", "fontFamily": "Pixel Arial 11 Bold", "shadowColor": "#D89494", - "shadowWidth": 2 + "shadowWidth": 2, }, "animations": [ @@ -33,20 +33,21 @@ To start off you must make a few assets (or use the default ones). Let's go over "name": "enter", "prefix": "speech bubble normal0", "offsets": [0, 0], - "frameRate": 24 + "frameRate": 24, }, { "name": "idle", "prefix": "speech bubble normal0", - "offsets": [0, 0] - } - ] + "offsets": [0, 0], + }, + ], } ``` The most important properties here are going to be the asset path, the textbox, and the animations. Fill these out to incoperate your custom assets, and put them into your mod under `assets/mods/MyDialogueMod/data/dialogue/boxes/myBox.json`. Next we can define some speakers with their own individual json, let's look at specfically boyfriend's pixel speaker.[^bfspeaker] + ```jsonc { "version": "1.0.0", @@ -60,13 +61,13 @@ Next we can define some speakers with their own individual json, let's look at s { "name": "talkEnter", "prefix": "portraitEnter0", - "frameRate": 12 + "frameRate": 12, }, { "name": "talk", - "prefix": "portraitTalk0" - } - ] + "prefix": "portraitTalk0", + }, + ], } ``` @@ -77,12 +78,11 @@ In conclusion, the assets you need are: - A font - A dialogue box - - - With an enter and normal animation + - With an enter and normal animation - A speaker + - With an enter and normal animation - - With an enter and normal animation ## Conversations Conversations, as the name implies are the conversations between two or more characters in a dialogue window. We can define these through json as well, as shown by the senpai conversation.[^senpaiconv] @@ -94,18 +94,18 @@ Conversations, as the name implies are the conversations between two or more cha "backdrop": { "type": "solid", "fadeTime": 2.0, - "color": "#BFB3DFD8" + "color": "#BFB3DFD8", }, "music": { "asset": "Lunchbox", "fadeTime": 2.0, - "looped": true + "looped": true, }, "outro": { "type": "fade", - "fadeTime": 1.0 + "fadeTime": 1.0, }, "dialogue": [ @@ -115,7 +115,7 @@ Conversations, as the name implies are the conversations between two or more cha "box": "roses", "boxAnimation": "enter", - "text": ["Ah, a new fair maiden has come in search of true love!"] + "text": ["Ah, a new fair maiden has come in search of true love!"], }, { "speaker": "senpai", @@ -124,8 +124,8 @@ Conversations, as the name implies are the conversations between two or more cha "boxAnimation": "speaking", "text": [ - "A serenade between gentlemen shall decide where her beautiful heart shall reside." - ] + "A serenade between gentlemen shall decide where her beautiful heart shall reside.", + ], }, { "speaker": "bf-pixel", @@ -133,9 +133,9 @@ Conversations, as the name implies are the conversations between two or more cha "box": "roses", "boxAnimation": "speaking", - "text": ["Beep bo bop"] - } - ] + "text": ["Beep bo bop"], + }, + ], } ``` @@ -225,8 +225,11 @@ As you can see, we define the same variables, create the same black rectangle, b In a minimal scenario, we really would just need to disable the input of the song, and then start the dialogue with `PlayState.instance.startConversation(string)` [^defbox]: + [^bfspeaker]: + [^senpaiconv]: + [^senpai]: -> Author: [Kade](https://github.com/Kade-github) \ No newline at end of file +> Author: [Kade](https://github.com/Kade-github) diff --git a/assets/content/cookbook/Advanced/09.VideoCutscenes.md b/assets/content/cookbook/Advanced/09.VideoCutscenes.md index c7f797362..6d882de32 100644 --- a/assets/content/cookbook/Advanced/09.VideoCutscenes.md +++ b/assets/content/cookbook/Advanced/09.VideoCutscenes.md @@ -29,7 +29,7 @@ class DetectedSong extends Song if (!hasPlayedCutscene) return; - + // We are playing the video cutscene hasPlayedCutscene = true; @@ -65,4 +65,4 @@ If we are in story mode, we cancel the event, create the black rectangle, and st Paths.videos prepends `assets/videos/videos/` to the path, so make sure your videos are in that path in your mod (ex: `mods/Hex-VSlice/videos/videos/detected.mp4`) -> Author: [Kade](https://github.com/Kade-github) \ No newline at end of file +> Author: [Kade](https://github.com/Kade-github) diff --git a/assets/content/cookbook/Advanced/10.ScriptedLevels.md b/assets/content/cookbook/Advanced/10.ScriptedLevels.md index ffadcc639..7aa95788a 100644 --- a/assets/content/cookbook/Advanced/10.ScriptedLevels.md +++ b/assets/content/cookbook/Advanced/10.ScriptedLevels.md @@ -28,6 +28,7 @@ You can then add override functions to perform custom behavior. ## Hiding specific Songs from the Menu By overriding the function `getSongDisplayNames`, you can hide certain songs from showing up on the story menu until a certain criteria is met. An example for this can be found in the script file for the Weekend 1 level.[^weekend1] + ```haxe // ... @@ -62,4 +63,4 @@ Even if you override `getSongDisplayNames`, the songs omitted will still be able [^weekend1]: -> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) \ No newline at end of file +> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) diff --git a/assets/content/cookbook/Advanced/11.ScriptedStages.md b/assets/content/cookbook/Advanced/11.ScriptedStages.md index a5e435e2c..cba05fe6a 100644 --- a/assets/content/cookbook/Advanced/11.ScriptedStages.md +++ b/assets/content/cookbook/Advanced/11.ScriptedStages.md @@ -28,6 +28,7 @@ You can then add override functions to perform custom behavior. ## Custom Behavior when adding a Character Considering characters get applied later in the initialization process, you would need to override the function `addCharacter` if you want to perform custom behavior involving characters. With this, you can set a shader to the added character immidiately after they're added. An example of this is found in the script for the stage Mall (Erect)[^mall] + ```haxe // ... @@ -47,7 +48,7 @@ override function addCharacter(character:BaseCharacter, charType:CharacterType): By overriding the function `buildStage`, you can set up custom behavior to activate when stage props get initialized. By doing this, you can immidiately apply a shader effect to props or instantly add scripted props to the stage. This is done in the stage script for Tankman Battlefield[^tank] -```haxe +```haxe // ... // Line 21 @@ -73,6 +74,7 @@ override function buildStage() ``` [^mall]: + [^tank]: -> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) \ No newline at end of file +> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) diff --git a/assets/content/cookbook/Advanced/12.ScriptedEvents.md b/assets/content/cookbook/Advanced/12.ScriptedEvents.md index 3077978a1..372dafc8f 100644 --- a/assets/content/cookbook/Advanced/12.ScriptedEvents.md +++ b/assets/content/cookbook/Advanced/12.ScriptedEvents.md @@ -1,4 +1,4 @@ -[tags]: / "advanced,hscript,events" +[tags]: / "advanced,hscript,events" # Scripted Song Events @@ -62,34 +62,28 @@ The game supports providing events some additional properties for more leeway in - `defaultValue`: An optional default value for the property. - `keys`: Is an optional map with keys representing the visible name and values representing the internal name of the property values. - - - Accessible to the `enum `properties. + - Accessible to the `enum `properties. - `min`: Represents the optional minimum value that the property could have. - - - Available to the `integer` and `float` properties. + - Available to the `integer` and `float` properties. - `max`: Represents the optional maximum value that the property could have. - - - Available to the `integer` and `float` properties. + - Available to the `integer` and `float` properties. - `step`: Represents the amount the value steps by for each change in the toolbox. This field is optional and defaults to `0.1`. - - - Available to the `integer` and `float` properties. + - Available to the `integer` and `float` properties. - `units`: Represents the unit of measure for the numeric value. (i.e. pixels, steps etc.) - - - Available to the `integer` and `float` properties. + - Available to the `integer` and `float` properties. ## Custom song event chart editor icon -Chart editor supports both static and animated song event icons in the spritesheet format. To provide a custom icon for your event in the chart editor, you need to put two things in the `mods/mymod/images/ui/chart-editor/events` folder: +Chart editor supports both static and animated song event icons in the spritesheet format. To provide a custom icon for your event in the chart editor, you need to put two things in the `mods/mymod/images/ui/chart-editor/events` folder: - An image of your song event icon named after what you put in the event's constructor. - An XML file for your song event icon, even if it's a single frame. - - - The frame names must start with the text you put inside the event's constructor. + - The frame names must start with the text you put inside the event's constructor. Once you made sure both assets are where they should be and have the correct names, your song event should have a custom icon in the chart editor. @@ -110,6 +104,7 @@ public override function getTitle():String ``` [^playanim]: + [^camzoom]: -> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) \ No newline at end of file +> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib) diff --git a/assets/content/cookbook/Expert/01.ScriptedModules.md b/assets/content/cookbook/Expert/01.ScriptedModules.md index 96d045b2a..402fdfa2f 100644 --- a/assets/content/cookbook/Expert/01.ScriptedModules.md +++ b/assets/content/cookbook/Expert/01.ScriptedModules.md @@ -52,4 +52,4 @@ Modules also have a priority system for compatibility with other mods, in your c You can view a detailed list of script events and their callbacks in [here](../Advanced/06.ScriptEventCallbacks.md) -> Author: [Kade](https://github.com/Kade-github) \ No newline at end of file +> Author: [Kade](https://github.com/Kade-github) diff --git a/assets/content/cookbook/Intermediate/01.CustomPlayableCharacters.md b/assets/content/cookbook/Intermediate/01.CustomPlayableCharacters.md index 2a292fc6b..2da33da8f 100644 --- a/assets/content/cookbook/Intermediate/01.CustomPlayableCharacters.md +++ b/assets/content/cookbook/Intermediate/01.CustomPlayableCharacters.md @@ -11,39 +11,37 @@ This chapter goes over adding new playable characters to the game, ensuring that In order to make a fleshed out custom character that can be used from Character Select in Friday Night Funkin', you need a large number of textures, animations, and audio tracks: - A [custom character](../Introduction/03.CustomCharacters.md). + - This requires a set of singing animations for the character. - - This requires a set of singing animations for the character. - At least one custom song that uses that character; this can be either [a new song](../Introduction/02.CustomSongs.md#adding-the-custom-song) or a [variation added to an existing song](../Introduction/02.CustomSongs.md#adding-variations-to-existing-songs). + - This requires an instrumental and split vocal tracks. - - This requires an instrumental and split vocal tracks. - A pixel icon asset to use for that character's icon in the Character Select grid. + - This supports either a static image or a Sparrow spritesheet (which includes the animation to play when the character is selected). - - This supports either a static image or a Sparrow spritesheet (which includes the animation to play when the character is selected). - A namecard asset to use for that character's name above them in the Character Select menu. + - The pixellation effect is done in code so this just needs to be a single static image. - - The pixellation effect is done in code so this just needs to be a single static image. - Animations for the character to use in the Character Select menu. + - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. + - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. - - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - Assets to use for the character's Girlfriend character to the left of them in the Character Select menu. + - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. + - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. - - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - Assets for the character to use on the Freeplay menu. + - This is currently hardcoded to use an Adobe Animate texture atlas. + - The character needs animations for leaping in, idle, confirm, and moving to character select. It also optionally has an idle and cartoon animation. - - This is currently hardcoded to use an Adobe Animate texture atlas. - - The character needs animations for leaping in, idle, confirm, and moving to character select. It also optionally has an idle and cartoon animation. - Assets for the character's Freeplay skin and the backing card. + - This requires a variety of assets but can use Boyfriend's as a fallback. + - NOTE: This is currently hardcoded to BF or Pico. - - This requires a variety of assets but can use Boyfriend's as a fallback. - - NOTE: This is currently hardcoded to BF or Pico. - Assets for the character's animations in the Results screen. - - - Each rank has its own animation and music, but animations can be reused between ranks and results themes can fall back to the default. - - Rank animations are Loss, Good, Great, Excellent, Perfect, and Perfect Gold (the base game uses the same animation for Perfect and Perfect Gold) - - Each also can take its own music, but you can reuse Boyfriend's as a good placeholder. - + - Each rank has its own animation and music, but animations can be reused between ranks and results themes can fall back to the default. + - Rank animations are Loss, Good, Great, Excellent, Perfect, and Perfect Gold (the base game uses the same animation for Perfect and Perfect Gold) + - Each also can take its own music, but you can reuse Boyfriend's as a good placeholder. # How to create a Playable Character @@ -58,7 +56,7 @@ A custom playable character requires creating a new JSON file in the `data/chara "pico-playable", "pico-blazin", "pico-christmas", - "pico-dark" + "pico-dark", ], "showUnownedChars": false, "unlocked": true, @@ -79,56 +77,56 @@ A custom playable character requires creating a new JSON file in the `data/chara "introBadEndFrame": 0, "loopBadStartFrame": 0, - "loopBadEndFrame": -1 + "loopBadEndFrame": -1, }, "charSelect": { - "transitionDelay": 0.45 + "transitionDelay": 0.45, }, "animations": [ { "name": "intro", "prefix": "pico dj intro", - "offsets": [631.7, 362.6] + "offsets": [631.7, 362.6], }, { "name": "idle", "prefix": "Pico DJ", - "offsets": [625, 360] + "offsets": [625, 360], }, { "name": "idleEasterEgg", "prefix": "Pico DJ afk", - "offsets": [625, 360] + "offsets": [625, 360], }, { "name": "confirm", "prefix": "Pico DJ confirm", - "offsets": [625, 360] + "offsets": [625, 360], }, { "name": "fistPump", "prefix": "pico cheer", - "offsets": [975, 260] + "offsets": [975, 260], }, { "name": "loss", "prefix": "Pico DJ loss", - "offsets": [625, 360] + "offsets": [625, 360], }, { "name": "charSelect", "prefix": "Pico DJ to CS", - "offsets": [625, 360] - } - ] + "offsets": [625, 360], + }, + ], }, "charSelect": { "position": 3, "gf": { "assetPath": "charSelect/neneChill", "animInfoPath": "charSelect/neneAnimInfo", - "visualizer": true - } + "visualizer": true, + }, }, "results": { "music": { @@ -137,7 +135,7 @@ A custom playable character requires creating a new JSON file in the `data/chara "EXCELLENT": "resultsEXCELLENT-pico", "GREAT": "resultsNORMAL-pico", "GOOD": "resultsNORMAL-pico", - "SHIT": "resultsSHIT-pico" + "SHIT": "resultsSHIT-pico", }, "perfectGold": [ { @@ -146,8 +144,8 @@ A custom playable character requires creating a new JSON file in the `data/chara "zIndex": 500, "scale": 0.88, "offsets": [385, 82], - "loopFrame": 91 - } + "loopFrame": 91, + }, ], "perfect": [ { @@ -156,8 +154,8 @@ A custom playable character requires creating a new JSON file in the `data/chara "zIndex": 500, "scale": 0.88, "offsets": [385, 82], - "loopFrame": 91 - } + "loopFrame": 91, + }, ], "excellent": [ { @@ -167,8 +165,8 @@ A custom playable character requires creating a new JSON file in the `data/chara "scale": 1.25, "offsets": [350, 25], "looped": true, - "loopFrame": 32 - } + "loopFrame": 32, + }, ], "great": [ { @@ -178,8 +176,8 @@ A custom playable character requires creating a new JSON file in the `data/chara "scale": 1.25, "offsets": [350, 25], "looped": true, - "loopFrame": 32 - } + "loopFrame": 32, + }, ], "good": [ { @@ -188,8 +186,8 @@ A custom playable character requires creating a new JSON file in the `data/chara "zIndex": 500, "scale": 1.25, "offsets": [350, 25], - "loopFrame": 41 - } + "loopFrame": 41, + }, ], "loss": [ { @@ -197,10 +195,10 @@ A custom playable character requires creating a new JSON file in the `data/chara "assetPath": "shared:resultScreen/results-pico/resultsSHIT", "zIndex": 500, "offsets": [-185, -125], - "loopFrame": 0 - } - ] - } + "loopFrame": 0, + }, + ], + }, } ``` @@ -209,15 +207,15 @@ The available fields are: - `version`: The version number for the Playable Character data file format. Leave this at `1.0.0`. - `name`: The readable name for the character, used internally. - `ownedCharacters`: The list of [Characters](../Introduction/03.CustomCharacters.md) this character owns. + - When determining which songs to display in Freeplay, the game checks for any songs where the player character is in this list and displays those. Songs where the player character is in another array are not displayed. - - When determining which songs to display in Freeplay, the game checks for any songs where the player character is in this list and displays those. Songs where the player character is in another array are not displayed. - `showUnownedChars`: If this value is `true`, then songs whose player character is not in any `ownedCharacters` list will be displayed for this character. - `unlocked`: Whether the character is unlocked. + - Create a scripted class for this playable character and override `isUnlocked():Bool` to make this conditional. See [Scripted Playable Characters](../Advanced/05.ScriptedPlayableCharacters.md) - - Create a scripted class for this playable character and override `isUnlocked():Bool` to make this conditional. See [Scripted Playable Characters](../Advanced/05.ScriptedPlayableCharacters.md) - `freeplayStyle`: The ID for a Freeplay style to display. + - You can use `"bf"` here to use Boyfriend's Freeplay style as a default, or create a new JSON file in the `data/ui/freeplay/styles` folder (copy the Pico one and edit that). - - You can use `"bf"` here to use Boyfriend's Freeplay style as a default, or create a new JSON file in the `data/ui/freeplay/styles` folder (copy the Pico one and edit that). - `freeplayDJ`: Data for how the character displays as the DJ in the Freeplay menu. - `charSelect`: Data for how the character displays in the Character Select menu. - `results`: Data for how the character displays in the Results screen. @@ -225,69 +223,65 @@ The available fields are: Freeplay DJ data is structured like so: - `assetPath`: The folder where the Animate Atlas for this character is located, relative to the `images/` folder. + - Note that Sparrow atlases are not supported for Freeplay animations. - - Note that Sparrow atlases are not supported for Freeplay animations. - `animations`: A list of animation data for the character. + - Valid animation names include `intro` `idle` `idleEasterEgg` `confirm` `fistPump` `loss` `charSelect` and ` - - Valid animation names include `intro` `idle` `idleEasterEgg` `confirm` `fistPump` `loss` `charSelect` and ` - `charSelect`: A structured data object containing: + - `transitionDelay`: A duration (in seconds) between when the character's transition to Character Select starts and the camera starts to fade. - - `transitionDelay`: A duration (in seconds) between when the character's transition to Character Select starts and the camera starts to fade. - `fistPump`: A structured data object containing: + - `introStartFrame` The frame number in the `fistPump` animation where the intro animation (which loops until the rank slams down) starts. + - `introEndFrame` The frame number in the `fistPump` animation where the intro animation ends. + - `loopStartFrame` The frame number in the `fistPump` animation where the follow-up animation starts. + - `loopEndFrame` The frame number in the `fistPump` animation where the follow-up animation ends. + - Use `-1` to use the last frame of the specified frame label. - - `introStartFrame` The frame number in the `fistPump` animation where the intro animation (which loops until the rank slams down) starts. - - `introEndFrame` The frame number in the `fistPump` animation where the intro animation ends. - - `loopStartFrame` The frame number in the `fistPump` animation where the follow-up animation starts. - - `loopEndFrame` The frame number in the `fistPump` animation where the follow-up animation ends. - - - Use `-1` to use the last frame of the specified frame label. - - `introBadStartFrame` The frame number in the `loss` animation where the intro animation starts. - - `introBadEndFrame` The frame number in the `loss` animation where the intro animation ends. - - `loopBadStartFrame` The frame number in the `loss` animation where the follow-up animation starts. - - `loopBadEndFrame` The frame number in the `loss` animation where the follow-up animation ends. + - `introBadStartFrame` The frame number in the `loss` animation where the intro animation starts. + - `introBadEndFrame` The frame number in the `loss` animation where the intro animation ends. + - `loopBadStartFrame` The frame number in the `loss` animation where the follow-up animation starts. + - `loopBadEndFrame` The frame number in the `loss` animation where the follow-up animation ends. Character Select data is structured like so: - `position`: The preferred grid square for the character in the Character Select grid. + - `0` represents the top left, `3` represents the middle left, and `8` represents the bottom right. + - Characters are evaluated alphabetically, and if the slot is already occupied, they will be shifted over until they fit. + - At time of writing (v0.5.1) only 9 total characters can fit in the grid. - - `0` represents the top left, `3` represents the middle left, and `8` represents the bottom right. - - Characters are evaluated alphabetically, and if the slot is already occupied, they will be shifted over until they fit. - - At time of writing (v0.5.1) only 9 total characters can fit in the grid. - `gf`: (NEW with v0.5.1) A structured data object containing: + - `assetPath`: The folder where the Animate Atlas for this character is located, relative to the `images/` folder. + - Note that Sparrow atlases are not supported. - - `assetPath`: The folder where the Animate Atlas for this character is located, relative to the `images/` folder. - - - Note that Sparrow atlases are not supported. - - `animInfoPath`: A path to a Flash JSFL file describing character sliding movement. - - `visualizer`: Whether the character is hooked up to display a visualizer (like Nene's ABot). - - - Check the Nene Character Select FLA to see how to implement this. + - `animInfoPath`: A path to a Flash JSFL file describing character sliding movement. + - `visualizer`: Whether the character is hooked up to display a visualizer (like Nene's ABot). + - Check the Nene Character Select FLA to see how to implement this. Results data is structured like so: - `music`: A structured data object containing: + - `PERFECT_GOLD`: The path to a music track in the `music/` folder. Played during the Perfect rank animation with all SICKs. + - `PERFECT`: The path to a music track in the `music/` folder. Played during the Perfect rank animation. + - `EXCELLENT`: The path to a music track in the `music/` folder. Played during the Excellent rank animation. + - `GREAT`: The path to a music track in the `music/` folder. Played during the Great rank animation. + - `GOOD`: The path to a music track in the `music/` folder. Played during the Good rank animation. + - `SHIT`: The path to a music track in the `music/` folder. Played during the Loss rank animation. + - Make sure to include a metadata file in the folder to tell the game what BPM the song is, and how to loop it. + - Include a variation of the track with the suffix `-intro.ogg` to play that track once before playing the main music track. - - `PERFECT_GOLD`: The path to a music track in the `music/` folder. Played during the Perfect rank animation with all SICKs. - - `PERFECT`: The path to a music track in the `music/` folder. Played during the Perfect rank animation. - - `EXCELLENT`: The path to a music track in the `music/` folder. Played during the Excellent rank animation. - - `GREAT`: The path to a music track in the `music/` folder. Played during the Great rank animation. - - `GOOD`: The path to a music track in the `music/` folder. Played during the Good rank animation. - - `SHIT`: The path to a music track in the `music/` folder. Played during the Loss rank animation. - - Make sure to include a metadata file in the folder to tell the game what BPM the song is, and how to loop it. - - Include a variation of the track with the suffix `-intro.ogg` to play that track once before playing the main music track. - `perfect`: An array of animation data structures, describing the animation played when the player gets a Perfect rank. + - Data is in the form of an array of animation objects. + - You can use Sparrow animations or `animateatlas` sprites. Use `renderType` to tell the game which one to use. + - Use `loopFrame` to tell the game which frame to start looping at, or set `looped` to `"false"` to just play the animation once. - - Data is in the form of an array of animation objects. - - You can use Sparrow animations or `animateatlas` sprites. Use `renderType` to tell the game which one to use. - - Use `loopFrame` to tell the game which frame to start looping at, or set `looped` to `"false"` to just play the animation once. - `excellent`: Data for the animation played when the player gets a Excellent rank. - `great`: Data for the animation played when the player gets a Great rank. - `good`: Data for the animation played when the player gets a Good rank. - `loss`: Data for the animation played when the player gets a Loss rank. - `perfectGold`: Data for the animation played when the player gets a Perfect rank with all SICKs. - - - In the base game, this is just the same data as `perfect`, but you can make it different if you like. + - In the base game, this is just the same data as `perfect`, but you can make it different if you like. [^picosource]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Intermediate/02.CustomNotestyles.md b/assets/content/cookbook/Intermediate/02.CustomNotestyles.md index 3d6e6795d..3668c1e15 100644 --- a/assets/content/cookbook/Intermediate/02.CustomNotestyles.md +++ b/assets/content/cookbook/Intermediate/02.CustomNotestyles.md @@ -47,8 +47,8 @@ Below is the "funkin" (aka the default) note style json file `assets/data/notest "left": { "prefix": "noteLeft" }, "down": { "prefix": "noteDown" }, "up": { "prefix": "noteUp" }, - "right": { "prefix": "noteRight" } - } + "right": { "prefix": "noteRight" }, + }, }, "noteStrumline": { "assetPath": "shared:noteStrumline", @@ -70,128 +70,127 @@ Below is the "funkin" (aka the default) note style json file `assets/data/notest "rightStatic": { "prefix": "staticRight0" }, "rightPress": { "prefix": "pressRight0" }, "rightConfirm": { "prefix": "confirmRight0" }, - "rightConfirmHold": { "prefix": "confirmRight0" } - } + "rightConfirmHold": { "prefix": "confirmRight0" }, + }, }, "holdNote": { "assetPath": "NOTE_hold_assets", - "data": {} + "data": {}, }, "noteSplash": { "assetPath": "", "data": { - "enabled": true - } + "enabled": true, + }, }, "holdNoteCover": { "assetPath": "", "data": { - "enabled": true - } + "enabled": true, + }, }, "countdownThree": { "data": { - "audioPath": "shared:gameplay/countdown/funkin/introTHREE" + "audioPath": "shared:gameplay/countdown/funkin/introTHREE", }, - "assetPath": null + "assetPath": null, }, "countdownTwo": { "data": { - "audioPath": "shared:gameplay/countdown/funkin/introTWO" + "audioPath": "shared:gameplay/countdown/funkin/introTWO", }, "assetPath": "shared:ui/countdown/funkin/ready", "scale": 1.0, - "isPixel": false + "isPixel": false, }, "countdownOne": { "data": { - "audioPath": "shared:gameplay/countdown/funkin/introONE" + "audioPath": "shared:gameplay/countdown/funkin/introONE", }, "assetPath": "shared:ui/countdown/funkin/set", "scale": 1.0, - "isPixel": false + "isPixel": false, }, "countdownGo": { "data": { - "audioPath": "shared:gameplay/countdown/funkin/introGO" + "audioPath": "shared:gameplay/countdown/funkin/introGO", }, "assetPath": "shared:ui/countdown/funkin/go", "scale": 1.0, - "isPixel": false + "isPixel": false, }, "judgementSick": { "assetPath": "default:ui/popup/funkin/sick", "scale": 0.65, - "isPixel": false + "isPixel": false, }, "judgementGood": { "assetPath": "default:ui/popup/funkin/good", "scale": 0.65, - "isPixel": false + "isPixel": false, }, "judgementBad": { "assetPath": "default:ui/popup/funkin/bad", "scale": 0.65, - "isPixel": false + "isPixel": false, }, "judgementShit": { "assetPath": "default:ui/popup/funkin/shit", "scale": 0.65, - "isPixel": false + "isPixel": false, }, "comboNumber0": { "assetPath": "default:ui/popup/funkin/num0", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber1": { "assetPath": "default:ui/popup/funkin/num1", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber2": { "assetPath": "default:ui/popup/funkin/num2", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber3": { "assetPath": "default:ui/popup/funkin/num3", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber4": { "assetPath": "default:ui/popup/funkin/num4", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber5": { "assetPath": "default:ui/popup/funkin/num5", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber6": { "assetPath": "default:ui/popup/funkin/num6", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber7": { "assetPath": "default:ui/popup/funkin/num7", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber8": { "assetPath": "default:ui/popup/funkin/num8", "isPixel": false, - "scale": 0.45 + "scale": 0.45, }, "comboNumber9": { "assetPath": "default:ui/popup/funkin/num9", "isPixel": false, - "scale": 0.45 - } - } + "scale": 0.45, + }, + }, } - ``` There is quite a lot to unravel, let's break it all down. @@ -201,7 +200,7 @@ There is quite a lot to unravel, let's break it all down. - `author`: The author of the note style, aka the artist who created the assets. - `fallback`: The note style ID to use as a fallback note style. Any assets not included for this note style will use the parent's asset instead. `"funkin"` is the recommended default in order to use the default base game assets for anything that is not specified. - `assets`: A list of asset data for each of the assets for the note style. - - See [list of assets](#note-style-assets) that you can provide the data for. + - See [list of assets](#note-style-assets) that you can provide the data for. Asset data is structured like so: @@ -248,4 +247,4 @@ Once the chart which references your note style is in your mod folder, simply st [^notestylesource]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Intermediate/03.CustomStickerPacks.md b/assets/content/cookbook/Intermediate/03.CustomStickerPacks.md index c793dda44..5240ae501 100644 --- a/assets/content/cookbook/Intermediate/03.CustomStickerPacks.md +++ b/assets/content/cookbook/Intermediate/03.CustomStickerPacks.md @@ -26,20 +26,20 @@ Below is the "default" sticker pack JSON file `assets/data/stickerpacks/default. "stickers": [ "transitionSwag/stickers-set-1/bfSticker1", "transitionSwag/stickers-set-1/bfSticker2", - "transitionSwag/stickers-set-1/bfSticker3" - ] + "transitionSwag/stickers-set-1/bfSticker3", + ], } ``` Let's break it all down. + - `version`: The version number for the Sticker Pack data file format. Leave this at `1.0.0`. + - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. - - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. - `name`: The readable name for the sticker pack, used in places like the Chart Editor. - `author`: The author of the sticker pack, aka the artist who created the assets. - `stickers`: A list of all the paths for all the stickers to use, as strings. - - - You cannot currently specify any additional arguments, such as scale, offsets, texture smoothing, or animations. + - You cannot currently specify any additional arguments, such as scale, offsets, texture smoothing, or animations. # Modifying an Existing Sticker Pack @@ -49,8 +49,8 @@ For example, to add to Boyfriend's standard sticker pack, you can use the follow ```jsonc [ - // Add an asset path to the end of the sticker list. - { "op": "add", "path": "/stickers/-", "value": "path/to/custom/sticker" } + // Add an asset path to the end of the sticker list. + { "op": "add", "path": "/stickers/-", "value": "path/to/custom/sticker" }, ] ``` @@ -69,4 +69,4 @@ The game checks and uses sticker packs in this order: [^stickerpacksource]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Intermediate/04.CustomAlbums.md b/assets/content/cookbook/Intermediate/04.CustomAlbums.md index 70c9abdce..23f5ae4b7 100644 --- a/assets/content/cookbook/Intermediate/04.CustomAlbums.md +++ b/assets/content/cookbook/Intermediate/04.CustomAlbums.md @@ -37,27 +37,26 @@ While there is not a lot, some stuff still need to be shown so you know what is - `albumArtAsset`: The asset path to the album art which will be displayed in Freeplay. - `albumTitleAsset`: The asset path to the album title which will be displayed below the album art in Freeplay. - `albumTitleOffsets`: The global offset to the album's position, in pixels. Optional, defaults to `[0, 0]`. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `albumTitleAnimations`: A list of animation data objects for the album title. Optional, defaults to `[]`, aka nothing. Animation data is structured like so: - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the asset to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. - - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. # Using the Album @@ -69,4 +68,4 @@ Once the song which references your album is in your mod folder, simply start th [^volume1]: -> Author: [anysad](https://github.com/anysad) \ No newline at end of file +> Author: [anysad](https://github.com/anysad) diff --git a/assets/content/cookbook/Intermediate/05.Migration.md b/assets/content/cookbook/Intermediate/05.Migration.md index ef08c9a63..9f163b804 100644 --- a/assets/content/cookbook/Intermediate/05.Migration.md +++ b/assets/content/cookbook/Intermediate/05.Migration.md @@ -17,30 +17,34 @@ In your mod's `_merge` folder, look for any `json` files and rewrite their conte ```jsonc // This is the format used by older versions of the game. { - "merge": [ - // Set `data.difficulty` to "super_hard" - { - "target": "data.difficulty", - "payload": "super_hard" - }, - // In the second element of the `data.nested.enemies` array, set `weapon` to "minigun" - { - "target": "data.nested.enemies[1].weapon", - "payload": "minigun" - } - ] + "merge": [ + // Set `data.difficulty` to "super_hard" + { + "target": "data.difficulty", + "payload": "super_hard", + }, + // In the second element of the `data.nested.enemies` array, set `weapon` to "minigun" + { + "target": "data.nested.enemies[1].weapon", + "payload": "minigun", + }, + ], } ``` ```jsonc // This is the format which will be used starting with v0.5.0. [ - { "op": "replace", "path": "/playData/characters/opponent", "value": "monster" }, // Replace the value of opponent with monster. + { + "op": "replace", + "path": "/playData/characters/opponent", + "value": "monster", + }, // Replace the value of opponent with monster. { "op": "add", "path": "/playData/characters/girlfriend", "value": "nene" }, // Add a new key girlfriend with the value Nene. { "op": "add", "path": "/playData/difficulties/1", "value": "funky" }, // Add a new value funky to the difficulty array, after easy { "op": "add", "path": "/playData/difficulties/-", "value": "expert" }, // Add a new value expert to the end of the difficulty array. { "op": "remove", "path": "/playData/garbageValue" }, // Remove the key garbageValue from the data entirely - { "op": "test", "path": "/playData/garbageValue", "value": 37 } // Test that a given value is in the JSON. If this operation fails, the patches will be rejected. + { "op": "test", "path": "/playData/garbageValue", "value": 37 }, // Test that a given value is in the JSON. If this operation fails, the patches will be rejected. ] ``` @@ -48,7 +52,7 @@ More information about this new system can be found at [Merging Files](../Introd ## Removal of Flixel UI -[Flixel UI](https://github.com/haxeflixel/flixel-ui) is a library used for developing creating UI elements and managing UI events in HaxeFlixel. In the past, this was used to power the UI of the Chart Editor, but the development team regularly found the library to be frustrating to use, and eventually switched to [HaxeUI](https://github.com/haxeui) for most of its user interfaces. +[Flixel UI](https://github.com/haxeflixel/flixel-ui) is a library used for developing creating UI elements and managing UI events in HaxeFlixel. In the past, this was used to power the UI of the Chart Editor, but the development team regularly found the library to be frustrating to use, and eventually switched to [HaxeUI](https://github.com/haxeui) for most of its user interfaces. In Friday Night Funkin' v0.5.0, the last places that the game used this library were refactored, and the game now exclusively uses a combination of manual sprite placement and HaxeUI for its user interfaces. As a result, Flixel UI was removed as a dependency. @@ -60,12 +64,12 @@ Once all the migration steps above have been performed, the last step is to modi ```jsonc { - // ... + // ... - // Change this value from "0.1.0" to "0.5.0" - "api_version": "0.5.0", + // Change this value from "0.1.0" to "0.5.0" + "api_version": "0.5.0", - // ... + // ... } ``` @@ -140,4 +144,4 @@ v0.6.0 rewrote how stickers get used by the game (and v0.6.3 rewrote it again bu New or updating mods looking to add, remove, or replace stickers should consult the [custom Sticker Packs documentation](03.CustomStickerPacks.md) -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Intermediate/06.CustomFreeplayStyles.md b/assets/content/cookbook/Intermediate/06.CustomFreeplayStyles.md index a75447c89..c80751655 100644 --- a/assets/content/cookbook/Intermediate/06.CustomFreeplayStyles.md +++ b/assets/content/cookbook/Intermediate/06.CustomFreeplayStyles.md @@ -25,20 +25,20 @@ Below is the "pico" freeplay style json file `assets/data/ui/freeplay/styles/pic Lets break it all down: - `version`: The version number for the Freeplay Style data file format. Leave this at `1.0.0`. + - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. - - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. - `bgAsset`: The asset path for the background to use for the Freeplay Style. - `selectorAsset`: The asset path for the difficulty selector sprites. - `numbersAsset`: The asset path for the score numbers. - `capsuleAsset`: The asset path for the song capsules. - `capsuleTextColors`: A list of two hex codes representing the colors for the capsule song name text outlines. + - The first color is for when the capsule is deselected, whereas the second one is for when the capsule is selected. As of now, the first color is unused. - - The first color is for when the capsule is deselected, whereas the second one is for when the capsule is selected. As of now, the first color is unused. - `startDelay`: The amount in seconds for the time needed to pass before switching to PlayState. # Using a Custom Freeplay Style -To use a freeplay style, you must first have a [Playable Character](1.CustomPlayableCharacters.md). You can set the value of the field `freeplayStyle` in your custom playable character to use your custom freeplay style or modify the value of other playable characters by using [JSONPatch](../Introduction/5.AppendingAndMerge.md#merging) to modify the `freeplayStyle` value of that character. +To use a freeplay style, you must first have a [Playable Character](1.CustomPlayableCharacters.md). You can set the value of the field `freeplayStyle` in your custom playable character to use your custom freeplay style or modify the value of other playable characters by using [JSONPatch](../Introduction/5.AppendingAndMerge.md#merging) to modify the `freeplayStyle` value of that character. [^pico]: diff --git a/assets/content/cookbook/Introduction/01.Introduction.md b/assets/content/cookbook/Introduction/01.Introduction.md index 89f01708b..144343823 100644 --- a/assets/content/cookbook/Introduction/01.Introduction.md +++ b/assets/content/cookbook/Introduction/01.Introduction.md @@ -1,4 +1,5 @@ [tags]: / "beginner,introduction" + # Fundamentals of Creating a Mod This guide will walk you through the process of creating a functioning, fully compatible Friday Night Funkin' mod, using the game's official systems for loading custom content and scripts. Once your mod is complete, you will be able to place it in the `mods` folder in your game install and use its content in-game without overriding the base game content and still maintain compatibility with other mods. @@ -17,18 +18,18 @@ Inside this file, we will put the information the game needs in order to learn a "description": "An introductory mod.", "contributors": [ { - "name": "EliteMasterEric" - } + "name": "EliteMasterEric", + }, ], "dependencies": { - "modA": "1.0.0" + "modA": "1.0.0", }, "optionalDependencies": { - "modB": "1.3.2" + "modB": "1.3.2", }, "api_version": "0.7.0", "mod_version": "1.0.0", - "license": "Apache-2.0" + "license": "Apache-2.0", } ``` @@ -51,9 +52,9 @@ Inside this file, we will put the information the game needs in order to learn a A Contributor has the following fields: - `name`: The contributor's name. -- `role`: *(optional)* The role the contributor played, for example "Artist" or "Programmer" -- `email`: *(optional)* A contact email -- `url`: *(optional)* A homepage URL +- `role`: _(optional)_ The role the contributor played, for example "Artist" or "Programmer" +- `email`: _(optional)_ A contact email +- `url`: _(optional)_ A homepage URL Many of these fields are intended to be used in the future by an upcoming Mod Menu interface, which will allow users to organize their mods. @@ -126,4 +127,4 @@ Thankfully, there is a better way! **Press F5 to force the game to dump its cach This chapter has covered the fundamentals of creating mods for Friday Night Funkin'. In other sections, we will go over how to add different types of custom content. -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Introduction/02.CustomSongs.md b/assets/content/cookbook/Introduction/02.CustomSongs.md index 55eaee6e9..616ec31b0 100644 --- a/assets/content/cookbook/Introduction/02.CustomSongs.md +++ b/assets/content/cookbook/Introduction/02.CustomSongs.md @@ -4,27 +4,22 @@ This chapter will walk you through the process of creating a functioning, fully compatible Friday Night Funkin' mod, using the game's official systems for loading custom content and scripts. Once your mod is complete, you will be able to place it in the `mods` folder in your game install and use its content in-game without overriding the base game content and still maintain compatibility with other mods. - This chapter goes over adding new playable songs and Story Mode levels to the game. # Creating a Chart To create a chart, access the Chart Editor tool. This can be found in-game by accessing the Debug menu from the main menu (this is bound to `~` by default). You can also access it by adding a keybind for "Debug Chart" in the options menu (not bound by default), then pressing the bound key while playing a song. - From here, you can create a new chart from audio files, import one from an older version of the game, or build a chart from existing in-game chart data. - Detailed use of the chart editor deserves its own guide, but the basic should be fairly intuitive. For now, let's assume you've made a chart of your favorite song, and want to turn it into a mod people can play. ## Dissecting Your FNFC File When you save your chart, the game packages it up into a `.fnfc` file, which makes it easy to share with other charters and collaborate. It includes the audio for the song, along with the note data and some metadata files to go with it. - To add the song to our mod, we need to get that info out. This is fairly easy, because an FNFC file is actually secretly a ZIP file! Rename your `mychart.fnfc` to `mychart.zip`, replacing the file extension so that your operating system recognizes it as a ZIP, and extract it to reveal its contents, which will be something like: - ``` -manifest.json -mychart-metadata.json @@ -38,12 +33,10 @@ To add the song to our mod, we need to get that info out. This is fairly easy, b At the end of [Creating A Chart](#creating-a-chart) we learned that `.fnfc` files were just `.zip` archives, so we can simply rename it and unzip it. Once we have thse files, we just need to put them in the correct spots in our mod folder! - - The `manifest.json` file can be discarded, our mod won't need it. - The `metadata.json` and `chart.json` files need to go into the `data/songs/` folder, replacing `` with the internal name for our song. - The OGG files need to go into `songs/`, again replacing `` with the internal name of our song. - We'll end up with something like this. ``` @@ -62,7 +55,6 @@ We'll end up with something like this. |-_polymod_meta.json ``` - When the game starts, it queries the list of available songs by looking in the `data/songs` folder for `/-metadata.json` files, which it then uses to find the chart file and the requisite song files. Neat! But right now, if you boot up the game, this doesn't do anything. You'll see it mentioned in the logs with no complaints, but it's not playable in Story Mode or Freeplay, what gives? ``` @@ -76,9 +68,7 @@ The fix is simple; every song must be part of a Story Mode level to appear in Fr Add a new file, with whatever internal name you like, into your mods folder, under the `data/levels/` directory, with the `.json` file extension. - -*NOTE*: Keep in mind that if your internal name is the same as a week from the base game, or of another mod, they will overlap each other and you may have unexpected results! - +_NOTE_: Keep in mind that if your internal name is the same as a week from the base game, or of another mod, they will overlap each other and you may have unexpected results! We'll end up with something like this. @@ -123,9 +113,9 @@ Your custom week's JSON file will look something like the following: { "name": "idle", "prefix": "idle0", - "frameRate": 24 - } - ] + "frameRate": 24, + }, + ], }, { "assetPath": "storymenu/props/bf", @@ -135,16 +125,16 @@ Your custom week's JSON file will look something like the following: { "name": "idle", "prefix": "idle0", - "frameRate": 24 + "frameRate": 24, }, { "name": "confirm", "prefix": "confirm0", - "frameRate": 24 - } - ] - } - ] + "frameRate": 24, + }, + ], + }, + ], } ``` @@ -158,26 +148,20 @@ There's a lot of info here! Let's break it down: - `visible`: Whether this story level is visible in the Story Menu. - `props`: Data for the props to display on the Story Menu when the level is selected. For example, Week 1 will display Daddy Dearest, Boyfriend, and Girlfriend. - When the game starts, it queries the list of available levels by looking in the `data/levels` folder for JSON files, which it then uses to populate the Story Menu, and then the Freeplay Menu (in non-alphabetical views, songs in Freeplay appear in order by what level they are included in). - If you want your custom song to only show up in Freeplay, you can just create a custom week and set the `visible` property to false, and the songs will show up in Freeplay! # What Are Variations? Variations are groups of difficulties for a given song which share metadata. - As an example, the song DadBattle has eight separate difficulties (at time of writing). These are Easy, Normal, Hard, Erect (Erect Mix), Nightmare (Erect Mix), Easy (Pico Mix), Normal (Pico Mix), and Hard (Pico Mix). - These are divided into three variations; Default, Erect, and Pico. Each variation defines information like BPM (and BPM changes), artist, charter, which album the song is from, which stage to use, which character to use in those stages, and which instrumental and vocal track to use. The variation then defines which difficulties it includes, and the chart data for that variation specifies the events for that variation, and the note data and scroll speed for each difficulty. - This means that, in order to make one of these values different for a specific difficulty or remix (including changing the events), you must put that difficulty into a new variation. - The `metadata.json` file for a song defines what variations exist for that song; the game then looks for `metadata-.json` and `chart-.json` files for each listed variation. # Adding Variations to Existing Songs @@ -188,7 +172,6 @@ Through modding, it is possible to add new variations to existing songs. This is The first step is to compose a new remix for the song. If you're making a playable character remix, the composer will have to manually make sure the original vocals line up if you want the option to use alternate instrumentals. - You then have to chart this remix. When you're done, you should have an `Inst.ogg` file, two `Voices` OGG files, a `metadata.json` and a `chart.json`. ## Placing the Files @@ -219,16 +202,15 @@ Each chart includes a `songVariations` array, which lets the game know which var If the base song you're adding the remix to is from your own mod, you can just add the variation to the `metadata.json` for your chart. - Add your variation ID to the `playData.songVariations` array (creating the key if it doesn't exist). ```jsonc { - "playData": { - "songVariations": ["erect"] // Add your new variation to this array. - // ... - } + "playData": { + "songVariations": ["erect"], // Add your new variation to this array. // ... + }, + // ... } ``` @@ -236,7 +218,6 @@ Add your variation ID to the `playData.songVariations` array (creating the key i If the base song you're adding to is from a different mod, you don't want to replace the underlying data in case it changes. You want to instead apply a JSON Patch to the file (which Polymod provides the ability to do). - Create a `_merge` folder in your mod folder, then create a file within that directory whose path matches the one you want to patch, like so: ``` @@ -253,7 +234,7 @@ Then we apply a simple patch, which adds a new value to the `playData.songVariat ```jsonc [ - { "op": "add", "path": "/playData/songVariations/-", "value": "erect" } // Add a new value erect to the end of the songVariations array. + { "op": "add", "path": "/playData/songVariations/-", "value": "erect" }, // Add a new value erect to the end of the songVariations array. ] ``` @@ -263,7 +244,6 @@ The patching system is very flexible; it works on any JSON file (base game or pr Now, when you start the game, your additional variation should be available in-game! - If you created a character remix, make sure the player character for the remix is included in the `ownedCharacters` data for your custom playable character. -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Introduction/03.CustomCharacters.md b/assets/content/cookbook/Introduction/03.CustomCharacters.md index ce6afb4d1..5649243d8 100644 --- a/assets/content/cookbook/Introduction/03.CustomCharacters.md +++ b/assets/content/cookbook/Introduction/03.CustomCharacters.md @@ -4,7 +4,6 @@ This chapter will walk you through the process of creating a functioning, fully compatible Friday Night Funkin' mod, using the game's official systems for loading custom content and scripts. Once your mod is complete, you will be able to place it in the `mods` folder in your game install and use its content in-game without overriding the base game content and still maintain compatibility with other mods. - This chapter goes over adding new characters to the game, and using them in a level. # Character Spritesheet Formats @@ -21,7 +20,7 @@ The individual sprites of a character's animations must be combined into a sprit # Creating a Character -A custom character requires creating a new JSON file in the `data/characters` folder. Below is an example +A custom character requires creating a new JSON file in the `data/characters` folder. Below is an example of Girlfriend's character data file, from `assets/data/characters/gf.json`[^gfsource] ```jsonc @@ -37,76 +36,76 @@ of Girlfriend's character data file, from `assets/data/characters/gf.json`[^gfso "name": "danceLeft", "prefix": "GF Dancing Beat", "frameIndices": [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], - "offsets": [0, -9] + "offsets": [0, -9], }, { "name": "danceRight", "prefix": "GF Dancing Beat", "frameIndices": [ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ], - "offsets": [0, -9] + "offsets": [0, -9], }, { "name": "sad", "prefix": "gf sad", "frameIndices": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], - "offsets": [2, -21] + "offsets": [2, -21], }, { "name": "singLEFT", "prefix": "GF left note", - "offsets": [0, -19] + "offsets": [0, -19], }, { "name": "singDOWN", "prefix": "GF Down Note", - "offsets": [0, -20] + "offsets": [0, -20], }, { "name": "singUP", "prefix": "GF Up Note", - "offsets": [0, 4] + "offsets": [0, 4], }, { "name": "singRIGHT", "prefix": "GF Right Note", - "offsets": [0, -20] + "offsets": [0, -20], }, { "name": "cheer", "prefix": "GF Cheer", - "offsets": [0, 0] + "offsets": [0, 0], }, { "name": "combo50", "prefix": "GF Cheer", - "offsets": [0, 0] + "offsets": [0, 0], }, { "name": "drop70", "prefix": "gf sad", "frameIndices": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], - "offsets": [2, -21] + "offsets": [2, -21], }, { "name": "hairBlow", "prefix": "GF Dancing Beat Hair blowing", "frameIndices": [0, 1, 2, 3], - "offsets": [45, -8] + "offsets": [45, -8], }, { "name": "hairFall", "prefix": "GF Dancing Beat Hair Landing", "frameIndices": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], - "offsets": [0, -9] + "offsets": [0, -9], }, { "name": "scared", "prefix": "GF FEAR", - "offsets": [-2, -17] - } - ] + "offsets": [-2, -17], + }, + ], } ``` @@ -117,33 +116,32 @@ The available fields are: - `renderType`: The render type. One of `sparrow`, `packer`, `animateatlas`, `multisparrow`. - `assetPath`: The main asset path to use for this character, relative to the `images` directory in your mod folder. + - For the `sparrow` asset type, this must point to the path where the `xml` and `png` are located, without the file extension. + - For the `packer` asset type, this must point to the path where the `txt` and `png` are located, without the file extension. + - For the `animateatlas` asset type, this must point to the folder where the `Animation.json` and any spritemaps are located. + - For the `multisparrow` asset type, point to the path where your main Sparrow spritesheet is located. On each animations which uses a different Sparrow spritesheet from the main one, add the `assetPath` key to that specific animation. - - For the `sparrow` asset type, this must point to the path where the `xml` and `png` are located, without the file extension. - - For the `packer` asset type, this must point to the path where the `txt` and `png` are located, without the file extension. - - For the `animateatlas` asset type, this must point to the folder where the `Animation.json` and any spritemaps are located. - - For the `multisparrow` asset type, point to the path where your main Sparrow spritesheet is located. On each animations which uses a different Sparrow spritesheet from the main one, add the `assetPath` key to that specific animation. -- `scale` *(currently buggy)*: Specify the size of the character relative to the original size. For example, `2.0` makes the sprite twice as big. Optional, defaults to `1.0`. +- `scale` _(currently buggy)_: Specify the size of the character relative to the original size. For example, `2.0` makes the sprite twice as big. Optional, defaults to `1.0`. - `healthIcon`: Data for the health icon to display in-game. For example, Boyfriend will obviously use Boyfriend's health icon. Optional, defaults its ID to character's ID. - `death`: Data for the death screen to use, when the character reaches `0` health. Optional, doesn't default to a specific object. - `offsets`: The global offset to the character's position, in pixels. Optional, defaults to `[0, 0]`. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `cameraOffsets`: The amount to offset the camera by while focusing on the character. Optional, default value focuses on the character directly. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `isPixel`: Specify whether to disable texture smoothing for the character. Optional, defaults to `false`. - `danceEvery`: The frequency at which the character will play its idle animation, in beats. Optional, defaults to `1`. + - Increasing this number will make the character dance less often. - - Increasing this number will make the character dance less often. - `flipX`: Whether to flip the whole sprite horizontally in-game. Useful for characters that could also be played (Pico). Optional, defaults to `false`. - `startingAnimation`: The animation for the character to play when they are first loaded in. Optional, defaults to `idle`. - `singTime`: The amount of time, in steps, for a character to keep singing after they let go of a note. Optional, defaults to `8`. + - Decrease this if the character seems to hold their poses for too long after their section is done. + - Increase this if the character resets to the idle animation in the middle of their singing animations. - - Decrease this if the character seems to hold their poses for too long after their section is done. - - Increase this if the character resets to the idle animation in the middle of their singing animations. - `animations`: A list of animation data objects for the character. - Health Icon data is structured like so: - `id`: The ID to use for the health icon, defaults to character's ID. @@ -151,40 +149,36 @@ Health Icon data is structured like so: - `flipX`: Whether to flip the whole sprite horizontally in-game. Optional, defaults to `false`. - `isPixel`: Specify whether to disable texture smoothing for this characters health icon. Optional, defaults to `false`. - `offsets`: The offset of the health icon, in pixels. Optional, defaults to `[0, 0]`. - - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. Death data is structured like so: - `cameraOffsets`: The amount to offset the camera by while focusing on this character as they die. Optional, defaults to `[0, 0]`. + - Default value focuses on the character's graphic midpoint. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Default value focuses on the character's graphic midpoint. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `cameraZoom`: The amount to zoom the camera by while focusing on this character as they die. Optional, defaults to `1`. - `preTransitionDelay`: The delay between when the character reaches `0` health and when the death animation plays. Optional, defaults to `0`. - Animation data is structured like so: - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. - The animation names the game uses by default are: - `idle`: For the idle animation. @@ -192,11 +186,11 @@ The animation names the game uses by default are: - `singLEFT`, `singDOWN`, `singUP`, `singRIGHT`: The animations for playing notes, when the character is a player or opponent. - `singLEFTmiss`, `singDOWNmiss`, `singUPmiss`, `singRIGHTmiss`: The animations for missing notes, when the character is a player. - Adding a new singing animation with the name of an existing animation with `-hold` at the end will play the animation after the first one ends, while the character is still singing. + - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - Adding a new singing animation with the name of an existing animation with `-end` at the end will play an animation before returning to idle. + - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - You can add other animations by name, but you'll have to play them with a script, or a `Play Animation` song event in the Chart Editor. When the game starts, it queries the list of possible characters by searching in the `data/characters` folder for JSON files. This gets used to preload data which is used later when the character is loaded in a stage. @@ -205,7 +199,6 @@ When the game starts, it queries the list of possible characters by searching in As a short aside, you can create a JSON with the same filename as an existing character (from the base game, or from a mod if your mod loads after it) and it will replace it. This can be used to create more elaborate reskins for characters, such as ones that use a different render type. - [^gfsource]: # Using a Character in a Song @@ -239,9 +232,10 @@ The UI will show you all of the possible controls and shortcuts, to make your pr ## Saving Offsets Once you are happy with your result, simply press `ESC` on your keyboard to save the `Character Data` file. + > [!NOTE] > In case you want to save the offsets of your character, you are able to do so by pressing `CTRL+ESC` on your keyboard to save the offsets. From the beginning of this chapter you will know, that you have to place this character data JSON file in `data/characters`. Then, you can simply use [Hot Reloading](../Introduction/01.Introduction.md#hot-reloading) to check the offsets without restarting the game. -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Introduction/04.CustomStages.md b/assets/content/cookbook/Introduction/04.CustomStages.md index d450d614c..5109217d1 100644 --- a/assets/content/cookbook/Introduction/04.CustomStages.md +++ b/assets/content/cookbook/Introduction/04.CustomStages.md @@ -30,7 +30,7 @@ Below is the "Main Stage" json file from Week 1 `assets/data/stages/mainStage.js "scale": [1, 1], "name": "stageBack", "assetPath": "stages/mainStage/stageback", - "scroll": [0.9, 0.9] + "scroll": [0.9, 0.9], }, { "zIndex": 20, @@ -38,7 +38,7 @@ Below is the "Main Stage" json file from Week 1 `assets/data/stages/mainStage.js "scale": [1.1, 1.1], "name": "stageFront", "assetPath": "stages/mainStage/stagefront", - "scroll": [0.9, 0.9] + "scroll": [0.9, 0.9], }, { "zIndex": 30, @@ -46,28 +46,27 @@ Below is the "Main Stage" json file from Week 1 `assets/data/stages/mainStage.js "scale": [0.9, 0.9], "name": "stageCurtains", "assetPath": "stages/mainStage/stagecurtains", - "scroll": [1.3, 1.3] - } + "scroll": [1.3, 1.3], + }, ], "characters": { "bf": { "zIndex": 300, "position": [989.5, 885], - "cameraOffsets": [-100, -100] + "cameraOffsets": [-100, -100], }, "dad": { "zIndex": 200, "position": [335, 885], - "cameraOffsets": [150, -100] + "cameraOffsets": [150, -100], }, "gf": { "zIndex": 100, "cameraOffsets": [0, 0], - "position": [751.5, 787] - } - } + "position": [751.5, 787], + }, + }, } - ``` The available fields are: @@ -80,7 +79,6 @@ The available fields are: Stage prop data is structured like so: - - `name`: An internal name for this prop. Good for keeping track of things. Keep each prop name unique! - You can access a stage prop in a script using `PlayState.instance.currentStage.getNamedProp(name)`. - `assetPath`: The asset used to display the prop. This can be either an image or a color. @@ -93,81 +91,78 @@ Stage prop data is structured like so: - `scale`: Specify the size of the prop relative to the original size. For example, `2.0` makes the sprite twice as big. Defaults to `1.0` if unspecified. - `alpha`: Specify the opacity of the prop, with `1.0` being fully opaque and `0.0` being completely transparent. Optional, defaults to `1.0`. - `scroll`: Specify how much scroll factor, or how much the prop moves relative to the camera horizontally and vertically. Defaults to `[0.0, 0.0]` if unspecified. + - A value of `[0, 0]` causes the prop to not move at all in relation to the camera. + - A value of `[1, 1]` causes the prop to move 1-to-1 with the camera. Characters usually have a scroll factor of `[1, 1]`. + - A value of `[0, 1]` causes the prop to only move vertically in relation to the camera as focus changes. + - A value of `[0.5, 0.5]` causes the prop to move less relative to props configured to move 1-to-1 + - A value of `[2, 2]` is valid and causes the prop to move 2-to-1 as the camera moves. - - A value of `[0, 0]` causes the prop to not move at all in relation to the camera. - - A value of `[1, 1]` causes the prop to move 1-to-1 with the camera. Characters usually have a scroll factor of `[1, 1]`. - - A value of `[0, 1]` causes the prop to only move vertically in relation to the camera as focus changes. - - A value of `[0.5, 0.5]` causes the prop to move less relative to props configured to move 1-to-1 - - A value of `[2, 2]` is valid and causes the prop to move 2-to-1 as the camera moves. - `animType`: If the prop you choose is animated, specify `sparrow` or `packer` for which animation type you're using. + - Most of the game's spritesheets are Sparrow v2 sheets exported from Adobe Animate. - - Most of the game's spritesheets are Sparrow v2 sheets exported from Adobe Animate. - `animations`: A list of animation data objects for the stage prop. - `startingAnimation`: The animation to play on the prop when the stage starts. If the animation is configured to loop, it will play forever unless a script calls a different one (or `danceEvery` is greater than 0). If unspecified, no animation will play unless a script does so. - `danceEvery`: If non-zero, this prop will play an animation every X beats of the song. Defaults to `0.0`, or no bopping. - - - This tries to play the `idle` animation. - - If `danceLeft` and `danceRight ` animations are specified, the game will alternate between these instead. - - This value supports precision up to `0.25`, where `0.25` plays the animation four times per beat. + - This tries to play the `idle` animation. + - If `danceLeft` and `danceRight ` animations are specified, the game will alternate between these instead. + - This value supports precision up to `0.25`, where `0.25` plays the animation four times per beat. Stage prop animation data is structured like so: - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. Character data is structured like so: - `bf`: Data about the stage's player character. + - `zIndex`: A value describing the relative position of the player character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - - `zIndex`: A value describing the relative position of the player character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - `dad`: Data about the stage's opponent character. + - `zIndex`: A value describing the relative position of the opponent character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - - `zIndex`: A value describing the relative position of the opponent character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - `gf`: Data about the stage's background character. - - - `zIndex`: A value describing the relative position of the background character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - + - `zIndex`: A value describing the relative position of the background character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. Animation data is structured like so: - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. The animation names the game uses by default are: @@ -177,11 +172,11 @@ The animation names the game uses by default are: - `singLEFT`, `singDOWN`, `singUP`, `singRIGHT`: The animations for playing notes, when the character is a player or opponent. - `singLEFTmiss`, `singDOWNmiss`, `singUPmiss`, `singRIGHTmiss`: The animations for missing notes, when the character is a player. - Adding a new singing animation with the name of an existing animation with `-hold` at the end will play the animation after the first one ends, while the character is still singing. + - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - Adding a new singing animation with the name of an existing animation with `-end` at the end will play an animation before returning to idle. + - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - You can add other animations by name, but you'll have to play them with a script, or a `Play Animation` song event in the Chart Editor. When the game starts, it queries the list of possible characters by searching in the `data/characters` folder for JSON files. This gets used to preload data which is used later when the character is loaded in a stage. @@ -197,4 +192,4 @@ Once the chart which references your stage is in your mod folder, simply start t [^stagesource]: -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/content/cookbook/Introduction/05.AppendingAndMerge.md b/assets/content/cookbook/Introduction/05.AppendingAndMerge.md index d7ec4fca8..428a53612 100644 --- a/assets/content/cookbook/Introduction/05.AppendingAndMerge.md +++ b/assets/content/cookbook/Introduction/05.AppendingAndMerge.md @@ -28,9 +28,9 @@ For example, given the source file `data/mydata.json`: { "test1": [1, 2, 3], "test2": { - "foo": "bar" + "foo": "bar", }, - "test3": "baz" + "test3": "baz", } ``` @@ -40,8 +40,8 @@ We can provide the file `mods/mymod/_append/data/mydata.json`: { "test4": "hello", "test2": { - "fizz": "buzz" - } + "fizz": "buzz", + }, } ``` @@ -53,11 +53,11 @@ And Polymod will mutate it to get this result: "test1": [1, 2, 3], // Included values are placed in directly, not merged! "test2": { - "fizz": "buzz" + "fizz": "buzz", }, "test3": "baz", // New values are simply included. - "test4": "hello" + "test4": "hello", } ``` @@ -70,6 +70,7 @@ Merging files into a data file is required for more complicated operations, such By using `_merge` files, rather than replacing the data files entirely, you make your mod fully compatible with both changes to the base game and to changes made by other mods. Merge files are applied in mod load order, meaning that multiple mods can make changes to the same file without any conflicts! ### Merging into TXT Files + **TODO** ### Merging into CSV/TSV Files @@ -112,11 +113,13 @@ Basically we want to change this one tag from this: ``` to this: + ```xml ``` This is the file you would put in `//data/stuff.xml`: + ```xml @@ -134,15 +137,16 @@ This file contains both data and merge instructions. The `` child tag tel The `` tag instructs the mod loader thus: -* Look for any tags with the same name as my parent (in this case, ``) -* Look within said tags for a `key` attribute (in this case, one named `"id"`) -* Check if the key's value matches what I'm looking for (in this case, `"difficulty"`) +- Look for any tags with the same name as my parent (in this case, ``) +- Look within said tags for a `key` attribute (in this case, one named `"id"`) +- Check if the key's value matches what I'm looking for (in this case, `"difficulty"`) As soon as it finds the first match, it stops and merges the payload with the specified tag. Any attributes will be added to the base tag (overwriting any existing attributes with the same name, which in this case changes values from "easy" to just "super_hard", which is what we want). Furthermore, if the payload has child nodes, all of its children will be merged with the target tag as well. ### Merging into JSON Files Merging into JSON files is done using a [JSON Patch](https://jsonpatch.com/) document. + > [!NOTE] > This significantly differs from JSON patch files created for v0.4.1 and earlier, which used a different system that honestly kinda sucked. @@ -154,14 +158,12 @@ Say we have a JSON data file `data/songs/mysong-metadata.json` like below: "playData": { "characters": { "player": "bf", - "opponent": "dad" + "opponent": "dad", }, - "difficulties": [ - "easy", "normal", "hard" - ], + "difficulties": ["easy", "normal", "hard"], "garbageValue": 37, - "stage": "mainStage" - } + "stage": "mainStage", + }, } ``` @@ -169,12 +171,16 @@ We can modify the above data with a document `mods/mymod/_merge/data/songs/myson ```jsonc [ - { "op": "replace", "path": "/playData/characters/opponent", "value": "monster" }, // Replace the value of opponent with monster. + { + "op": "replace", + "path": "/playData/characters/opponent", + "value": "monster", + }, // Replace the value of opponent with monster. { "op": "add", "path": "/playData/characters/girlfriend", "value": "nene" }, // Add a new key girlfriend with the value Nene. { "op": "add", "path": "/playData/difficulties/1", "value": "funky" }, // Add a new value funky to the difficulty array, after easy { "op": "add", "path": "/playData/difficulties/-", "value": "expert" }, // Add a new value expert to the end of the difficulty array. { "op": "remove", "path": "/playData/garbageValue" }, // Remove the key garbageValue from the data entirely - { "op": "test", "path": "/playData/garbageValue", "value": 37 } // Test that a given value is in the JSON. If this operation fails, the patches will be rejected. + { "op": "test", "path": "/playData/garbageValue", "value": 37 }, // Test that a given value is in the JSON. If this operation fails, the patches will be rejected. ] ``` @@ -186,4 +192,4 @@ The `path` must be a string of either property names or array indexes (starting The `path` may also be a JSONPath string, which allows robustly specifying a target path with support for filtering logic. You can read more here: https://goessner.net/articles/JsonPath/ -> Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file +> Author: [EliteMasterEric](https://github.com/EliteMasterEric) diff --git a/assets/includes/css/font-awesome.css b/assets/includes/css/font-awesome.css index 168a93e61..bccffbbc3 100644 --- a/assets/includes/css/font-awesome.css +++ b/assets/includes/css/font-awesome.css @@ -5,9 +5,15 @@ /* FONT PATH * -------------------------- */ @font-face { - font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=4.1.0'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); + font-family: "FontAwesome"; + src: url("../fonts/fontawesome-webfont.eot?v=4.1.0"); + src: + url("../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0") + format("embedded-opentype"), + url("../fonts/fontawesome-webfont.woff?v=4.1.0") format("woff"), + url("../fonts/fontawesome-webfont.ttf?v=4.1.0") format("truetype"), + url("../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular") + format("svg"); font-weight: normal; font-style: normal; } @@ -61,9 +67,9 @@ left: -1.85714286em; } .fa-border { - padding: .2em .25em .15em; + padding: 0.2em 0.25em 0.15em; border: solid 0.08em #eeeeee; - border-radius: .1em; + border-radius: 0.1em; } .pull-right { float: right; @@ -72,10 +78,10 @@ float: left; } .fa.pull-left { - margin-right: .3em; + margin-right: 0.3em; } .fa.pull-right { - margin-left: .3em; + margin-left: 0.3em; } .fa-spin { -webkit-animation: spin 2s infinite linear; @@ -1563,4 +1569,4 @@ } .fa-bomb:before { content: "\f1e2"; -} \ No newline at end of file +} diff --git a/assets/includes/css/fonts.css b/assets/includes/css/fonts.css index d997d5dfa..e7aa1b5bf 100644 --- a/assets/includes/css/fonts.css +++ b/assets/includes/css/fonts.css @@ -1,16 +1,27 @@ /* latin-ext */ @font-face { - font-family: 'Open Sans'; + font-family: "Open Sans"; font-style: normal; font-weight: 400; - src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/open-sans-latin-ext.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + src: + local("Open Sans Regular"), + local("OpenSans-Regular"), + url(../fonts/open-sans-latin-ext.woff2) format("woff2"); + unicode-range: + U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, + U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Open Sans'; + font-family: "Open Sans"; font-style: normal; font-weight: 400; - src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/open-sans-latin.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} \ No newline at end of file + src: + local("Open Sans Regular"), + local("OpenSans-Regular"), + url(../fonts/open-sans-latin.woff2) format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; +} diff --git a/assets/includes/css/haxe-nav.css b/assets/includes/css/haxe-nav.css index 8f04723f0..fa594955e 100644 --- a/assets/includes/css/haxe-nav.css +++ b/assets/includes/css/haxe-nav.css @@ -1,166 +1,205 @@ nav.nav { - font-family: "Open Sans", sans-serif; - font-size: 16px; - margin:0; + font-family: "Open Sans", sans-serif; + font-size: 16px; + margin: 0; } nav .fa { - color:#777; - margin-right:5px; + color: #777; + margin-right: 5px; } -body nav * {line-height:20px;} +body nav * { + line-height: 20px; +} nav .navbar-inverse .navbar-inner { - background:#13110f; - border:0; + background: #13110f; + border: 0; } nav .navbar .nav { - margin:0; + margin: 0; } nav .dropdown-menu { - background:#2c2722; - font-size: 14px; - border-radius:0px 0px 2px 2px; - padding:10px 0px; - border:1px solid #2c2722; - margin-top:-1px; + background: #2c2722; + font-size: 14px; + border-radius: 0px 0px 2px 2px; + padding: 10px 0px; + border: 1px solid #2c2722; + margin-top: -1px; } -nav .navbar .nav>li>a { - padding: 14px 12px 15px 12px; - color:#ccc; +nav .navbar .nav > li > a { + padding: 14px 12px 15px 12px; + color: #ccc; } nav .dropdown-menu li a { - color: #b8b5b5; - padding:3px 15px; + color: #b8b5b5; + padding: 3px 15px; } nav .divider { - background-color:transparent; - border-right:1px solid #39332d; - margin:5px 20px 5px 10px; - height:39px; + background-color: transparent; + border-right: 1px solid #39332d; + margin: 5px 20px 5px 10px; + height: 39px; } nav .dropdown-menu .divider { - background-color:transparent; - border:0; - border-bottom:1px solid #39332d; - margin:5px 0; + background-color: transparent; + border: 0; + border-bottom: 1px solid #39332d; + margin: 5px 0; } -nav .navbar-inverse .nav .active>a, nav .navbar-inverse .nav .active>a:hover, nav .navbar-inverse .nav .active>a:focus, nav .navbar-inverse .nav li.dropdown.open>.dropdown-toggle, nav .navbar-inverse .nav li.dropdown.active>.dropdown-toggle, nav .navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle { - color: #fff; - background-color:transparent; - background-image:none; +nav .navbar-inverse .nav .active > a, +nav .navbar-inverse .nav .active > a:hover, +nav .navbar-inverse .nav .active > a:focus, +nav .navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +nav .navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +nav .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #fff; + background-color: transparent; + background-image: none; } - nav .navbar-inverse .nav .active>a:hover { - background:#39332d; +nav .navbar-inverse .nav .active > a:hover { + background: #39332d; } -nav .dropdown-menu>.active>a, nav .dropdown-menu>.active>a:hover, nav .dropdown-menu>.active>a:focus { - font-weight:bold; - color: #fff; - background-image:none; - background:#39332d; +nav .dropdown-menu > .active > a, +nav .dropdown-menu > .active > a:hover, +nav .dropdown-menu > .active > a:focus { + font-weight: bold; + color: #fff; + background-image: none; + background: #39332d; } -nav .dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus, nav .dropdown-submenu:hover>a, nav .dropdown-submenu:focus>a { - background:#39332d; +nav .dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +nav .dropdown-submenu:hover > a, +nav .dropdown-submenu:focus > a { + background: #39332d; } -nav .navbar .nav>li>.dropdown-menu:after { - border-bottom-color:#2c2722; +nav .navbar .nav > li > .dropdown-menu:after { + border-bottom-color: #2c2722; } /** MEDIA Q **/ -@media (max-width: 979px) -{ - nav .navbar-fixed-top .navbar-inner, nav .navbar-fixed-bottom .navbar-inner { - padding: 0px; - } - nav .navbar-fixed-top { - margin-bottom: 0; - } - .nav .divider { - display: none; - } +@media (max-width: 979px) { + nav .navbar-fixed-top .navbar-inner, + nav .navbar-fixed-bottom .navbar-inner { + padding: 0px; + } + nav .navbar-fixed-top { + margin-bottom: 0; + } + .nav .divider { + display: none; + } } /** SUB BRAND LOGOS **/ -.navbar .brand.haxe-logo { position:relative; padding-right:0; margin: 3px 0 0 0px; right: 5px; } -.navbar .brand.haxe-logo:hover { opacity:.9; } +.navbar .brand.haxe-logo { + position: relative; + padding-right: 0; + margin: 3px 0 0 0px; + right: 5px; +} +.navbar .brand.haxe-logo:hover { + opacity: 0.9; +} .navbar .brand.haxe-logo:after { - content:" "; - position:absolute; - /* create arrow */ - width: 0; - height: 0; - margin:0 5px 0 5px; - border-top: 22px solid transparent; - border-bottom: 22px solid transparent; - border-left: 7px solid #13110f; /* same color as nav bar */ - top:0; -} -.navbar .brand.sub { - background: #39332d; /* Old browsers */ - background: -moz-linear-gradient(top, #39332d 50%, #2c2722 51%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(50%,#39332d), color-stop(51%,#2c2722)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #39332d 50%,#2c2722 51%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #39332d 50%,#2c2722 51%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, #39332d 50%,#2c2722 51%); /* IE10+ */ - background: linear-gradient(to bottom, #39332d 50%,#2c2722 51%); /* W3C */ - padding:14px 20px 13px 20px; - margin:0 10px 0 0; - font:bold 18px "arial black", "open sans"; - line-height:26px; - color:rgb(255,255,255); + content: " "; + position: absolute; + /* create arrow */ + width: 0; + height: 0; + margin: 0 5px 0 5px; + border-top: 22px solid transparent; + border-bottom: 22px solid transparent; + border-left: 7px solid #13110f; /* same color as nav bar */ + top: 0; +} +.navbar .brand.sub { + background: #39332d; /* Old browsers */ + background: -moz-linear-gradient(top, #39332d 50%, #2c2722 51%); /* FF3.6+ */ + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(50%, #39332d), + color-stop(51%, #2c2722) + ); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient( + top, + #39332d 50%, + #2c2722 51% + ); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient( + top, + #39332d 50%, + #2c2722 51% + ); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #39332d 50%, #2c2722 51%); /* IE10+ */ + background: linear-gradient(to bottom, #39332d 50%, #2c2722 51%); /* W3C */ + padding: 14px 20px 13px 20px; + margin: 0 10px 0 0; + font: + bold 18px "arial black", + "open sans"; + line-height: 26px; + color: rgb(255, 255, 255); } .navbar .brand.sub:hover { - color:rgb(230,230,230); - background: #2c2722; /* Old browsers */ + color: rgb(230, 230, 230); + background: #2c2722; /* Old browsers */ } .navbar .brand.sub:before { - position:absolute; - margin-left:-33px; - margin-top:-28px; - line-height:0px; - font:bold 40px "Open Sans", sans-serif; - letter-spacing:0px; - color:#fff200; + position: absolute; + margin-left: -33px; + margin-top: -28px; + line-height: 0px; + font: + bold 40px "Open Sans", + sans-serif; + letter-spacing: 0px; + color: #fff200; } -.navbar .sub { - text-shadow: 1px 1px 3px #000; +.navbar .sub { + text-shadow: 1px 1px 3px #000; - margin-left: -10px; + margin-left: -10px; - font: 18px "Open Sans", sans-serif; - line-height:22px; - color:rgb(255,255,255); + font: + 18px "Open Sans", + sans-serif; + line-height: 22px; + color: rgb(255, 255, 255); } /** SUB BRAND COLORS **/ .navbar .brand.sub.try:before { - color:#f89c0e; + color: #f89c0e; } .navbar .brand.sub.api:before { - color:#eedc16; + color: #eedc16; } .navbar .brand.sub.lib:before { - color:#f1471d; + color: #f1471d; } .navbar .brand.sub.ide:before { - color:#f89c0e; + color: #f89c0e; } diff --git a/assets/includes/css/styles.css b/assets/includes/css/styles.css index 0e47227ee..80443a66a 100644 --- a/assets/includes/css/styles.css +++ b/assets/includes/css/styles.css @@ -9,27 +9,39 @@ body { } html { - scroll-padding-top:50px; + scroll-padding-top: 50px; } -body, body p, body td, body li { +body, +body p, +body td, +body li { line-height: 1.5; } -.btn, .btn-large, .btn-medium, .btn-small { - border-radius: 4px!important; - margin-right:5px; +.btn, +.btn-large, +.btn-medium, +.btn-small { + border-radius: 4px !important; + margin-right: 5px; } .main-content { - flex: 1 0 auto; + flex: 1 0 auto; } h1 { font-weight: normal; } -h1,h2,h3,h4,h5,h6, #title { +h1, +h2, +h3, +h4, +h5, +h6, +#title { font-weight: normal; } @@ -42,29 +54,40 @@ h3 code { } pre code { - font-size: 14px; + font-size: 14px; } #title { font-size: 38.5px; } -article h1, article h2, article h3, article h4, article h5, article h6 { - margin-bottom:20px; +article h1, +article h2, +article h3, +article h4, +article h5, +article h6 { + margin-bottom: 20px; } -article h2, article h3, article h4, article h5, article h6 { - margin-top:20px; +article h2, +article h3, +article h4, +article h5, +article h6 { + margin-top: 20px; } article h3 { - border-bottom:1px dotted #ddd; + border-bottom: 1px dotted #ddd; } article h2 { - border-bottom:1px dotted #aaa; + border-bottom: 1px dotted #aaa; } -a, a:hover, a > code { +a, +a:hover, +a > code { color: #257fc2; } @@ -81,28 +104,32 @@ a, a:hover, a > code { } .authors img { - margin-bottom: 2px; + margin-bottom: 2px; } .contributors a { - margin-bottom: 2px; + margin-bottom: 2px; } .crumb span[itemprop="itemListElement"]:not(:last-child):after { - content: ' › '; + content: " › "; } @media (max-width: 767px) { - body {padding:0} + body { + padding: 0; + } .container { padding: 0 20px; margin: 0; } - .navbar-fixed-top, .navbar-fixed-bottom, .navbar-static-top { + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { margin-left: 0; margin-right: 0; } - + main.container section { display: flex; flex-direction: column; @@ -113,24 +140,24 @@ a, a:hover, a > code { main.container section nav { order: 2; } - + nav#sidebar { - margin-top:20px; + margin-top: 20px; } - + /* only display main categories on mobile */ - nav#sidebar.sidebar-toc li li { - display:none; + nav#sidebar.sidebar-toc li li { + display: none; } nav#sidebar.sidebar-toc br { - display:none; + display: none; } - + /* display tags inline on mobile */ - nav#sidebar.sidebar-tags li { - display:inline-block; - border-left:0; - margin-right:20px; + nav#sidebar.sidebar-tags li { + display: inline-block; + border-left: 0; + margin-right: 20px; } } @@ -138,7 +165,7 @@ a, a:hover, a > code { body .hero-unit h3 { font-size: 90%; } - + body .hero-unit { padding: 2em; } @@ -149,7 +176,8 @@ a, a:hover, a > code { } @media (min-width: 979px) { - .hero-unit, .hero-unit-small { + .hero-unit, + .hero-unit-small { margin-top: 49px; } @@ -158,15 +186,39 @@ a, a:hover, a > code { } } -.hero-unit, .hero-unit-small { - background: #FBC707; - +.hero-unit, +.hero-unit-small { + background: #fbc707; + background-repeat: no-repeat; - background: -webkit-gradient(radial, 50% 80%, 0, center center, 100, from(183,77,49), to(100,33,38)); - background: -webkit-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); - background: -moz-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); - background: -ms-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); - + background: -webkit-gradient( + radial, + 50% 80%, + 0, + center center, + 100, + from(183, 77, 49), + to(100, 33, 38) + ); + background: -webkit-radial-gradient( + 50% 80%, + circle, + rgb(183, 77, 49), + rgb(100, 33, 38) + ); + background: -moz-radial-gradient( + 50% 80%, + circle, + rgb(183, 77, 49), + rgb(100, 33, 38) + ); + background: -ms-radial-gradient( + 50% 80%, + circle, + rgb(183, 77, 49), + rgb(100, 33, 38) + ); + color: #f0f0f0; text-align: center; border-radius: 0; @@ -175,32 +227,37 @@ a, a:hover, a > code { .hero-unit { padding: 4em; margin-bottom: 0; - box-shadow: inset 0px 0px 50px rgba(0,0,0, 0.35); + box-shadow: inset 0px 0px 50px rgba(0, 0, 0, 0.35); } .hero-unit-small { padding: 2em 0; margin-bottom: 1.5em; border-bottom: 15px solid #eee; - box-shadow: inset 0px 0px 50px rgba(0,0,0, 0.3); + box-shadow: inset 0px 0px 50px rgba(0, 0, 0, 0.3); } -.hero-unit h1, #title, .hero-unit-small h1 { +.hero-unit h1, +#title, +.hero-unit-small h1 { color: #fff; - text-shadow:2px 2px 2px rgba(0,0,0,.15); + text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } -.hero-unit h1 small, #title small, .hero-unit-small h1 small { - color: #C06B69; +.hero-unit h1 small, +#title small, +.hero-unit-small h1 small { + color: #c06b69; } -.hero-unit-small h1, .hero-unit-small #title { +.hero-unit-small h1, +.hero-unit-small #title { margin-bottom: 0em; } .logo { width: 80%; - max-width: 140px; + max-width: 140px; max-height: 230px; margin: 1em; } @@ -208,27 +265,28 @@ a, a:hover, a > code { .hero-unit-small .logo { margin: 1%; margin: 0em; - max-width: 401px; + max-width: 401px; max-height: 90px; } .hero-unit h3.lead { - color: #EA8220; + color: #ea8220; } -.hero-unit a, .hero-unit a:hover { - color: #FBC707; +.hero-unit a, +.hero-unit a:hover { + color: #fbc707; text-decoration: none; border-bottom: 1px dashed #fff; } .dark { - background: rgb(20,20,25); + background: rgb(20, 20, 25); color: #fff; } .dark-section { - background: rgb(20,20,25); + background: rgb(20, 20, 25); color: #fff; padding: 2em 1em; } @@ -247,9 +305,9 @@ footer { } .reading-time { - position:relative; - top:-1em; - font-style:italic; + position: relative; + top: -1em; + font-style: italic; font-size: 90%; } @@ -270,21 +328,21 @@ blockquote { } blockquote.author-info { - border-left: 4px solid #EA8220; + border-left: 4px solid #ea8220; } .markdown-alert { padding: 0.5rem 1rem; margin-bottom: 1rem; color: inherit; - border-left: .25em solid #d1d9e0; + border-left: 0.25em solid #d1d9e0; } -.markdown-alert>:first-child { +.markdown-alert > :first-child { margin-top: 0; } -.markdown-alert>:last-child { +.markdown-alert > :last-child { margin-top: 0; } @@ -338,20 +396,27 @@ blockquote.author-info { color: #d1242f; } -.dark a, .dark a:hover, .dark a:active { - color: rgb(234,130,32); +.dark a, +.dark a:hover, +.dark a:active { + color: rgb(234, 130, 32); } -.dark a.flashdevelop, .dark a.flashdevelop:hover, .dark a.flashdevelop:active { +.dark a.flashdevelop, +.dark a.flashdevelop:hover, +.dark a.flashdevelop:active { color: #eee; text-decoration: underline; } .btn-success { - background: rgb(234,130,32); + background: rgb(234, 130, 32); } -.btn-success:hover,.btn-success:focus, .btn-success:active, .btn-success.active { +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active { color: #ffffff; background: #e5801f; } @@ -383,57 +448,60 @@ nav#sidebar li li a { } article table { - min-width:100%; + min-width: 100%; } article table tr:not(:last-child) { - border-bottom:1px solid #ccc; + border-bottom: 1px solid #ccc; } -article table td:not(:first-child), article table th:not(:first-child) { - border-left:1px solid #ccc; +article table td:not(:first-child), +article table th:not(:first-child) { + border-left: 1px solid #ccc; } -article table td, article table th { - padding:3px 5px; - text-align:left; +article table td, +article table th { + padding: 3px 5px; + text-align: left; } -article table td:first-child, article table th:first-child { - width:140px; +article table td:first-child, +article table th:first-child { + width: 140px; } -code.prettyprint { +code.prettyprint { padding: 0.5em; display: block; } -.tag { - padding-left:5px; - padding-right:10px; +.tag { + padding-left: 5px; + padding-right: 10px; } .tag small { - color:#999; - font-size:80%; + color: #999; + font-size: 80%; } .tag a { - color:#A84B38; + color: #a84b38; } .tag a:hover { - color:#EA8220; + color: #ea8220; } .fa { - color:#555; + color: #555; } .fa-big { - font-size:32px; - color:#555; - padding-left:15px; - padding-right:15px; + font-size: 32px; + color: #555; + padding-left: 15px; + padding-right: 15px; } .btn { @@ -441,35 +509,38 @@ code.prettyprint { } .try-haxe { - width:100%; - height:350px; - margin:0; - border:0px; + width: 100%; + height: 350px; + margin: 0; + border: 0px; } .page-list-item:not(last-child) { - margin-bottom:20px; + margin-bottom: 20px; } .page-list-item p { - margin-left:10px; + margin-left: 10px; } .page-list h4 { - font-weight:normal; + font-weight: normal; } .page-list-item { - padding: 1px 15px 15px 15px; - border: 1px solid #eeeeee; - border-radius: 5px; - background:#fdfdfd; + padding: 1px 15px 15px 15px; + border: 1px solid #eeeeee; + border-radius: 5px; + background: #fdfdfd; } -.g-plus, #___plus_0 { vertical-align: text-bottom !important; } -.twitter-share-button { vertical-align: text-bottom !important; } - - +.g-plus, +#___plus_0 { + vertical-align: text-bottom !important; +} +.twitter-share-button { + vertical-align: text-bottom !important; +} .flex-video { position: relative; @@ -480,8 +551,12 @@ code.prettyprint { overflow: hidden; } -.flex-video.widescreen { padding-bottom: 57.25%; } -.flex-video.vimeo { padding-top: 0; } +.flex-video.widescreen { + padding-bottom: 57.25%; +} +.flex-video.vimeo { + padding-top: 0; +} .flex-video iframe, .flex-video object, @@ -493,6 +568,12 @@ code.prettyprint { height: 100%; } -@media only screen and (max-device-width: 800px), only screen and (device-width: 1024px) and (device-height: 600px), only screen and (width: 1280px) and (orientation: landscape), only screen and (device-width: 800px), only screen and (max-width: 767px) { - .flex-video { padding-top: 0; } -} \ No newline at end of file +@media only screen and (max-device-width: 800px), + only screen and (device-width: 1024px) and (device-height: 600px), + only screen and (width: 1280px) and (orientation: landscape), + only screen and (device-width: 800px), + only screen and (max-width: 767px) { + .flex-video { + padding-top: 0; + } +} diff --git a/assets/includes/css/styles.min.css b/assets/includes/css/styles.min.css index 0105766de..facdec010 100644 --- a/assets/includes/css/styles.min.css +++ b/assets/includes/css/styles.min.css @@ -1 +1 @@ -body{font-family:"Open Sans",sans-serif;font-weight:400;font-size:16px;color:#1e1e1e;display:flex;flex-direction:column;height:100vh}html {scroll-padding-top:50px;}body,body li,body p,body td{line-height:1.5}.btn,.btn-large,.btn-medium,.btn-small{border-radius:4px!important;margin-right:5px}.main-content{flex:1 0 auto}h1{font-weight:400}#title,h1,h2,h3,h4,h5,h6{font-weight:400}article h4{font-weight:700}h3 code{font-size:20px}pre code{font-size:14px}#title{font-size:38.5px}article h1,article h2,article h3,article h4,article h5,article h6{margin-bottom:20px}article h2,article h3,article h4,article h5,article h6{margin-top:20px}article h3{border-bottom:1px dotted #ddd}article h2{border-bottom:1px dotted #aaa}a,a:hover,a>code{color:#257fc2}.contribution{color:#ccc}.contribution a{color:#444}.contribution .fa{color:#999}.authors img{margin-bottom:2px}.contributors a{margin-bottom:2px}.crumb span[itemprop=itemListElement]:not(:last-child):after{content:' › '}@media (max-width:767px){body{padding:0}.container{padding:0 20px;margin:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{margin-left:0;margin-right:0}main.container section{display:flex;flex-direction:column}main.container section article{order:1}main.container section nav{order:2}nav#sidebar{margin-top:20px}nav#sidebar.sidebar-toc li li{display:none}nav#sidebar.sidebar-toc br{display:none}nav#sidebar.sidebar-tags li{display:inline-block;border-left:0;margin-right:20px}}@media (max-width:500px){body .hero-unit h3{font-size:90%}body .hero-unit{padding:2em}body .hero-unit h3 br{display:none}}@media (min-width:979px){.hero-unit,.hero-unit-small{margin-top:49px}body .hero-unit h3 br{display:block}}.hero-unit,.hero-unit-small{background:#fbc707;background-repeat:no-repeat;background:-webkit-gradient(radial,50% 80%,0,center center,100,from(183,77,49),to(100,33,38));background:-webkit-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-moz-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-ms-radial-gradient(50% 80%,circle,#b74d31,#642126);color:#f0f0f0;text-align:center;border-radius:0}.hero-unit{padding:4em;margin-bottom:0;box-shadow:inset 0 0 50px rgba(0,0,0,.35)}.hero-unit-small{padding:2em 0;margin-bottom:1.5em;border-bottom:15px solid #eee;box-shadow:inset 0 0 50px rgba(0,0,0,.3)}#title,.hero-unit h1,.hero-unit-small h1{color:#fff;text-shadow:2px 2px 2px rgba(0,0,0,.15)}#title small,.hero-unit h1 small,.hero-unit-small h1 small{color:#c06b69}.hero-unit-small #title,.hero-unit-small h1{margin-bottom:0}.logo{width:80%;max-width:140px;max-height:230px;margin:1em}.hero-unit-small .logo{margin:1%;margin:0;max-width:401px;max-height:90px}.hero-unit h3.lead{color:#ea8220}.hero-unit a,.hero-unit a:hover{color:#fbc707;text-decoration:none;border-bottom:1px dashed #fff}.dark{background:#141419;color:#fff}.dark-section{background:#141419;color:#fff;padding:2em 1em}footer{margin-top:40px;font-size:14px;flex-shrink:0}.copyright{padding:6px;overflow:hidden;text-align:center;margin:40px 0}.reading-time{position:relative;top:-1em;font-style:italic;font-size:90%}.footnotes{font-size:0.85em;overflow-wrap:anywhere;}.footnote-ref a:target{scroll-margin-top: 40vh;}blockquote{margin-left:30px;border-left:4px solid #eee;font-style:italic;padding:15px 15px 15px 30px}blockquote.author-info{border-left:4px solid #ea8220}.markdown-alert{padding:0.5rem 1rem;margin-bottom: 1rem;color:inherit;border-left:.25em solid #d1d9e0;}.markdown-alert>:first-child{margin-top:0}.markdown-alert>:last-child{margin-bottom:0}.markdown-alert-image{margin-right:8px;}.markdown-alert .markdown-alert-title{display:flex;font-weight:bold;align-items:center;line-height:1;}.markdown-alert.markdown-alert-note{border-left-color:#0969da;}.markdown-alert.markdown-alert-note .markdown-alert-title{color:#0969da;}.markdown-alert.markdown-alert-important{border-left-color:#8250df;}.markdown-alert.markdown-alert-important .markdown-alert-title{color:#8250df;}.markdown-alert.markdown-alert-warning {border-left-color:#9a6700;}.markdown-alert.markdown-alert-warning .markdown-alert-title{color:#9a6700;}.markdown-alert.markdown-alert-tip{border-left-color:#1a7f37;}.markdown-alert.markdown-alert-tip .markdown-alert-title{color:#1a7f37;}.markdown-alert.markdown-alert-caution{border-left-color:#cf222e;}.markdown-alert.markdown-alert-caution .markdown-alert-title{color:#d1242f;}.dark a,.dark a:active,.dark a:hover{color:#ea8220}.dark a.flashdevelop,.dark a.flashdevelop:active,.dark a.flashdevelop:hover{color:#eee;text-decoration:underline}.btn-success{background:#ea8220}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover{color:#fff;background:#e5801f}nav#sidebar *{line-height:1.5em}nav#sidebar li.active{font-weight:700}nav#sidebar li.active li{font-weight:400}nav#sidebar li{border-left:1px solid #ccc;padding-left:10px}nav#sidebar li li{border-left:0;font-size:14px}nav#sidebar li li a{color:#777}article table{min-width:100%}article table tr:not(:last-child){border-bottom:1px solid #ccc}article table td:not(:first-child),article table th:not(:first-child){border-left:1px solid #ccc}article table td,article table th{padding:3px 5px;text-align:left}article table td:first-child,article table th:first-child{width:140px}code.prettyprint{padding:.5em;display:block}.tag{padding-left:5px;padding-right:10px}.tag small{color:#999;font-size:80%}.tag a{color:#a84b38}.tag a:hover{color:#ea8220}.fa{color:#555}.fa-big{font-size:32px;color:#555;padding-left:15px;padding-right:15px}.btn{margin-bottom:5px}.try-haxe{width:100%;height:350px;margin:0;border:0}.page-list-item:not(last-child){margin-bottom:20px}.page-list-item p{margin-left:10px}.page-list h4{font-weight:400}.page-list-item{padding:1px 15px 15px 15px;border:1px solid #eee;border-radius:5px;background:#fdfdfd}#___plus_0,.g-plus{vertical-align:text-bottom!important}.twitter-share-button{vertical-align:text-bottom!important}.flex-video{position:relative;padding-top:25px;padding-bottom:67.5%;height:0;margin-bottom:16px;overflow:hidden}.flex-video.widescreen{padding-bottom:57.25%}.flex-video.vimeo{padding-top:0}.flex-video embed,.flex-video iframe,.flex-video object{position:absolute;top:0;left:0;width:100%;height:100%}@media only screen and (max-device-width:800px),only screen and (device-width:1024px) and (device-height:600px),only screen and (width:1280px) and (orientation:landscape),only screen and (device-width:800px),only screen and (max-width:767px){.flex-video{padding-top:0}} \ No newline at end of file +body{font-family:"Open Sans",sans-serif;font-weight:400;font-size:16px;color:#1e1e1e;display:flex;flex-direction:column;height:100vh}html{scroll-padding-top:50px}body,body li,body p,body td{line-height:1.5}.btn,.btn-large,.btn-medium,.btn-small{border-radius:4px!important;margin-right:5px}.main-content{flex:1 0 auto}h1{font-weight:400}#title,h1,h2,h3,h4,h5,h6{font-weight:400}article h4{font-weight:700}h3 code{font-size:20px}pre code{font-size:14px}#title{font-size:38.5px}article h1,article h2,article h3,article h4,article h5,article h6{margin-bottom:20px}article h2,article h3,article h4,article h5,article h6{margin-top:20px}article h3{border-bottom:1px dotted #ddd}article h2{border-bottom:1px dotted #aaa}a,a:hover,a>code{color:#257fc2}.contribution{color:#ccc}.contribution a{color:#444}.contribution .fa{color:#999}.authors img{margin-bottom:2px}.contributors a{margin-bottom:2px}.crumb span[itemprop=itemListElement]:not(:last-child):after{content:" › "}@media (max-width:767px){body{padding:0}.container{padding:0 20px;margin:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{margin-left:0;margin-right:0}main.container section{display:flex;flex-direction:column}main.container section article{order:1}main.container section nav{order:2}nav#sidebar{margin-top:20px}nav#sidebar.sidebar-toc li li{display:none}nav#sidebar.sidebar-toc br{display:none}nav#sidebar.sidebar-tags li{display:inline-block;border-left:0;margin-right:20px}}@media (max-width:500px){body .hero-unit h3{font-size:90%}body .hero-unit{padding:2em}body .hero-unit h3 br{display:none}}@media (min-width:979px){.hero-unit,.hero-unit-small{margin-top:49px}body .hero-unit h3 br{display:block}}.hero-unit,.hero-unit-small{background:#fbc707;background-repeat:no-repeat;background:-webkit-gradient(radial,50% 80%,0,center center,100,from(183,77,49),to(100,33,38));background:-webkit-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-moz-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-ms-radial-gradient(50% 80%,circle,#b74d31,#642126);color:#f0f0f0;text-align:center;border-radius:0}.hero-unit{padding:4em;margin-bottom:0;box-shadow:inset 0 0 50px rgba(0,0,0,.35)}.hero-unit-small{padding:2em 0;margin-bottom:1.5em;border-bottom:15px solid #eee;box-shadow:inset 0 0 50px rgba(0,0,0,.3)}#title,.hero-unit h1,.hero-unit-small h1{color:#fff;text-shadow:2px 2px 2px rgba(0,0,0,.15)}#title small,.hero-unit h1 small,.hero-unit-small h1 small{color:#c06b69}.hero-unit-small #title,.hero-unit-small h1{margin-bottom:0}.logo{width:80%;max-width:140px;max-height:230px;margin:1em}.hero-unit-small .logo{margin:1%;margin:0;max-width:401px;max-height:90px}.hero-unit h3.lead{color:#ea8220}.hero-unit a,.hero-unit a:hover{color:#fbc707;text-decoration:none;border-bottom:1px dashed #fff}.dark{background:#141419;color:#fff}.dark-section{background:#141419;color:#fff;padding:2em 1em}footer{margin-top:40px;font-size:14px;flex-shrink:0}.copyright{padding:6px;overflow:hidden;text-align:center;margin:40px 0}.reading-time{position:relative;top:-1em;font-style:italic;font-size:90%}.footnotes{font-size:.85em;overflow-wrap:anywhere}.footnote-ref a:target{scroll-margin-top:40vh}blockquote{margin-left:30px;border-left:4px solid #eee;font-style:italic;padding:15px 15px 15px 30px}blockquote.author-info{border-left:4px solid #ea8220}.markdown-alert{padding:.5rem 1rem;margin-bottom:1rem;color:inherit;border-left:.25em solid #d1d9e0}.markdown-alert>:first-child{margin-top:0}.markdown-alert>:last-child{margin-top:0}.markdown-alert-image{margin-right:8px}.markdown-alert .markdown-alert-title{display:flex;font-weight:700;align-items:center;line-height:1}.markdown-alert.markdown-alert-note{border-left-color:#0969da}.markdown-alert.markdown-alert-note .markdown-alert-title{color:#0969da}.markdown-alert.markdown-alert-important{border-left-color:#8250df}.markdown-alert.markdown-alert-important .markdown-alert-title{color:#8250df}.markdown-alert.markdown-alert-warning{border-left-color:#9a6700}.markdown-alert.markdown-alert-warning .markdown-alert-title{color:#9a6700}.markdown-alert.markdown-alert-tip{border-left-color:#1a7f37}.markdown-alert.markdown-alert-tip .markdown-alert-title{color:#1a7f37}.markdown-alert.markdown-alert-caution{border-left-color:#cf222e}.markdown-alert.markdown-alert-caution .markdown-alert-title{color:#d1242f}.dark a,.dark a:active,.dark a:hover{color:#ea8220}.dark a.flashdevelop,.dark a.flashdevelop:active,.dark a.flashdevelop:hover{color:#eee;text-decoration:underline}.btn-success{background:#ea8220}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover{color:#fff;background:#e5801f}nav#sidebar *{line-height:1.5em}nav#sidebar li.active{font-weight:700}nav#sidebar li.active li{font-weight:400}nav#sidebar li{border-left:1px solid #ccc;padding-left:10px}nav#sidebar li li{border-left:0;font-size:14px}nav#sidebar li li a{color:#777}article table{min-width:100%}article table tr:not(:last-child){border-bottom:1px solid #ccc}article table td:not(:first-child),article table th:not(:first-child){border-left:1px solid #ccc}article table td,article table th{padding:3px 5px;text-align:left}article table td:first-child,article table th:first-child{width:140px}code.prettyprint{padding:.5em;display:block}.tag{padding-left:5px;padding-right:10px}.tag small{color:#999;font-size:80%}.tag a{color:#a84b38}.tag a:hover{color:#ea8220}.fa{color:#555}.fa-big{font-size:32px;color:#555;padding-left:15px;padding-right:15px}.btn{margin-bottom:5px}.try-haxe{width:100%;height:350px;margin:0;border:0}.page-list-item:not(last-child){margin-bottom:20px}.page-list-item p{margin-left:10px}.page-list h4{font-weight:400}.page-list-item{padding:1px 15px 15px 15px;border:1px solid #eee;border-radius:5px;background:#fdfdfd}#___plus_0,.g-plus{vertical-align:text-bottom!important}.twitter-share-button{vertical-align:text-bottom!important}.flex-video{position:relative;padding-top:25px;padding-bottom:67.5%;height:0;margin-bottom:16px;overflow:hidden}.flex-video.widescreen{padding-bottom:57.25%}.flex-video.vimeo{padding-top:0}.flex-video embed,.flex-video iframe,.flex-video object{position:absolute;top:0;left:0;width:100%;height:100%}@media only screen and (max-device-width:800px),only screen and (device-width:1024px) and (device-height:600px),only screen and (width:1280px) and (orientation:landscape),only screen and (device-width:800px),only screen and (max-width:767px){.flex-video{padding-top:0}} \ No newline at end of file diff --git a/assets/includes/js/404.js b/assets/includes/js/404.js index 4b0bb6220..62ada9a7f 100644 --- a/assets/includes/js/404.js +++ b/assets/includes/js/404.js @@ -1,32 +1,37 @@ /** * @author Mark Knol */ -(function() { +(function () { var pages = window.pages; var searchResults = []; var path = window.location.href.split("/").pop().split(".").shift(); console.log(path); - for(var i=0;i"+searchResults[i].title+""; + html += "


Page not found

Did you mean:

"; + html += "" + html += ""; document.getElementById("result404").innerHTML = html; } -})(); \ No newline at end of file +})(); diff --git a/authoring.md b/authoring.md index 30ee0cf6f..7c4eca35e 100644 --- a/authoring.md +++ b/authoring.md @@ -1,6 +1,6 @@ # Authoring Funkin' CookBook Articles -So you think you're cool enough to write some tutorials? +So you think you're cool enough to write some tutorials? Well, that's great! Here is all you need to know about how to write and maintain articles on this CookBook! @@ -10,13 +10,13 @@ Basic quality standards are required for each article, and are the exact same as ## Naming/File Structure -Files should be stored inside of `assets/content/cookbook/`, in *sub-directories* of the article's top-level difficulty. So something that would be for beginners would be in `assets/content/cookbook/Introduction`, as an example. +Files should be stored inside of `assets/content/cookbook/`, in _sub-directories_ of the article's top-level difficulty. So something that would be for beginners would be in `assets/content/cookbook/Introduction`, as an example. The naming convention of those articles should follow Pascal Case and be prepended with the number in that series they represent. We also prepend `0` if the number isn't two digits, this helps the site actually figure out which article comes first! -`Introduction/03.CustomCharacters.md` is an example of the correct scheme. With "Introduction" being the *sub-directory* +`Introduction/03.CustomCharacters.md` is an example of the correct scheme. With "Introduction" being the _sub-directory_ ## Formatting @@ -27,7 +27,6 @@ To indicate the topic of the article, we format the tags as so, `[tags]: / "begi You should always sign your name at the bottom of the file, after footnote definitions. A correct example looks like this: ```markdown - ... [^philly]: @@ -39,9 +38,9 @@ Otherwise, traditional markdown is the standard. This file is an example of such ## Embedding/Code blocks -We use code blocks very frequently, and they're incredibly useful. To keep them that way for the user, always remember to have your code blocks **syntax highlighted**. The currently supported highlighting styles are: `jsonc` (we use jsonc because it includes support for comments!), `haxe` (use this for .hxc as well), `js`, and `xml`. If you have a file type that isn't supported, please make an issue or find said *TM Bundle* to make a pull request! (Grammars can be found in `grammars/`) +We use code blocks very frequently, and they're incredibly useful. To keep them that way for the user, always remember to have your code blocks **syntax highlighted**. The currently supported highlighting styles are: `jsonc` (we use jsonc because it includes support for comments!), `haxe` (use this for .hxc as well), `js`, and `xml`. If you have a file type that isn't supported, please make an issue or find said _TM Bundle_ to make a pull request! (Grammars can be found in `grammars/`) -When embedding a file, you must also include a footnote to that file if it is also found on a **FunkinCrew**, *or really any* git repository. You can find a very detailed guide on footnotes (and many other cool markdown features) [here](https://www.markdownguide.org/extended-syntax/#footnotes) +When embedding a file, you must also include a footnote to that file if it is also found on a **FunkinCrew**, _or really any_ git repository. You can find a very detailed guide on footnotes (and many other cool markdown features) [here](https://www.markdownguide.org/extended-syntax/#footnotes) ## Tagging @@ -56,4 +55,4 @@ Some great practices (that aren't required) can also be done in your article! A - Including lists of properties and a description of each. - Linking to different articles or helpful pages. - Using backquotes to signify property names or important code names/values. (ex: `name`, `[1,2,3,4]`) -- If naming a property, classifying if it is read only or not. \ No newline at end of file +- If naming a property, classifying if it is read only or not. diff --git a/package-lock.json b/package-lock.json index 3e1b7c19f..763d2dfd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,32 +1,22 @@ { "name": "code-cookbook", "version": "0.1.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "code-cookbook", "version": "0.1.0", "devDependencies": { - "concurrently": "^9.2.1", "cson-parser": "3.0.0", "http-server": "^14.1.1", "less": "^4.4.1", "less-plugin-clean-css": "^1.6.0", + "prettier": "^3.6.2", "vscode-oniguruma": "^2.0.1", "vscode-textmate": "^9.1.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -137,21 +127,6 @@ "node": ">= 10.0" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/coffeescript": { "version": "1.12.7", "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", @@ -185,31 +160,6 @@ "dev": true, "license": "MIT" }, - "node_modules/concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, "node_modules/copy-anything": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", @@ -275,13 +225,6 @@ "node": ">= 0.4" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -329,16 +272,6 @@ "node": ">= 0.4" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -377,16 +310,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -576,16 +499,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", @@ -764,6 +677,22 @@ "node": ">= 10.12" } }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -788,16 +717,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -805,16 +724,6 @@ "dev": true, "license": "MIT" }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -855,19 +764,6 @@ "semver": "bin/semver" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -954,60 +850,6 @@ "node": ">=0.10.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1058,791 +900,6 @@ "engines": { "node": ">=12" } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - } - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - } - }, - "call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "requires": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "coffeescript": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", - "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", - "dev": true, - "requires": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - } - }, - "copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "requires": { - "is-what": "^3.14.1" - } - }, - "corser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", - "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", - "dev": true - }, - "cson-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-3.0.0.tgz", - "integrity": "sha512-khmLtNmwe6SSlWz5vrhay9yWd/Fwwyiel+vt+1vIcCT9AsdqNuLXuK9tYhhAw1FdSSHjLc56PW8xa565/x73XQ==", - "dev": true, - "requires": { - "coffeescript": "^1.10.0" - } - }, - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "requires": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "requires": { - "prr": "~1.0.1" - } - }, - "es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true - }, - "es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "requires": { - "es-errors": "^1.3.0" - } - }, - "escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "requires": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - } - }, - "get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "requires": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - } - }, - "gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true - }, - "hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-server": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", - "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", - "dev": true, - "requires": { - "basic-auth": "^2.0.1", - "chalk": "^4.1.2", - "corser": "^2.0.1", - "he": "^1.2.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy": "^1.18.1", - "mime": "^1.6.0", - "minimist": "^1.2.6", - "opener": "^1.5.1", - "portfinder": "^1.0.28", - "secure-compare": "3.0.1", - "union": "~0.5.0", - "url-join": "^4.0.1" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "less": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/less/-/less-4.4.1.tgz", - "integrity": "sha512-X9HKyiXPi0f/ed0XhgUlBeFfxrlDP3xR4M7768Zl+WXLUViuL9AOPPJP4nCV0tgRWvTYvpNmN0SFhZOQzy16PA==", - "dev": true, - "requires": { - "copy-anything": "^2.0.1", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "parse-node-version": "^1.0.1", - "source-map": "~0.6.0", - "tslib": "^2.3.0" - } - }, - "less-plugin-clean-css": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/less-plugin-clean-css/-/less-plugin-clean-css-1.6.0.tgz", - "integrity": "sha512-jwXX6WlXT57OVCXa5oBJBaJq1b4s1BOKeEEoAL2UTeEitogQWfTcBbLT/vow9pl0N0MXV8Mb4KyhTGG0YbEKyQ==", - "dev": true, - "requires": { - "clean-css": "5.3.3" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - } - }, - "object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true - }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true - }, - "portfinder": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", - "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", - "dev": true, - "requires": { - "async": "^3.2.6", - "debug": "^4.3.6" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, - "requires": { - "side-channel": "^1.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true, - "optional": true - }, - "secure-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", - "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", - "dev": true - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "optional": true - }, - "shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true - }, - "side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "requires": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - } - }, - "side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "requires": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - } - }, - "side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - } - }, - "side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, - "tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true - }, - "union": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", - "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", - "dev": true, - "requires": { - "qs": "^6.4.0" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "vscode-oniguruma": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-2.0.1.tgz", - "integrity": "sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ==", - "dev": true - }, - "vscode-textmate": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.1.0.tgz", - "integrity": "sha512-lxKSVp2DkFOx9RDAvpiYUrB9/KT1fAfi1aE8CBGstP8N7rLF+Seifj8kDA198X0mYj1CjQUC+81+nQf8CO0nVA==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true } } } diff --git a/package.json b/package.json index 038c8e547..21afcb2cd 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "build": "npm run css && npm run haxe", "css": "lessc assets/includes/css/styles.css assets/includes/css/styles.min.css --clean-css='--s1 --advanced --compatibility=ie8'", "haxe": "haxe build.hxml", - "dev": "http-server -c-1 --cors -s -o output" + "dev": "http-server -c-1 --cors -s -o output", + "prettier:check": "prettier . --check", + "prettier:write": "prettier . --write" }, "devDependencies": { "cson-parser": "3.0.0", @@ -13,6 +15,7 @@ "less-plugin-clean-css": "^1.6.0", "vscode-oniguruma": "^2.0.1", "vscode-textmate": "^9.1.0", - "http-server": "^14.1.1" + "http-server": "^14.1.1", + "prettier": "^3.6.2" } } diff --git a/utterances.json b/utterances.json index 5a02f8e83..a37211d47 100644 --- a/utterances.json +++ b/utterances.json @@ -1,3 +1,3 @@ { - "origins": ["http://localhost","https://thekade.net/funkin-cookbook/"] + "origins": ["http://localhost", "https://thekade.net/funkin-cookbook/"] }