https://github.com/maz01001/other-projects
other small projects not hosted on my GitHub-page
https://github.com/maz01001/other-projects
ascii-game cmd cpp game games snake-game
Last synced: 17 days ago
JSON representation
other small projects not hosted on my GitHub-page
- Host: GitHub
- URL: https://github.com/maz01001/other-projects
- Owner: MAZ01001
- License: mit
- Created: 2021-05-04T16:06:48.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2026-03-17T10:21:08.000Z (4 months ago)
- Last Synced: 2026-03-18T01:26:31.144Z (4 months ago)
- Topics: ascii-game, cmd, cpp, game, games, snake-game
- Language: C#
- Homepage:
- Size: 203 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Random projects
Other _small_ projects that don't have their own repo (yet?)
or aren't strongly related to [Math-JS](https://github.com/MAZ01001/Math-Js "My Math-js repo")
also...other languages than javascript ?! :o
- [snake_cmd-game.cpp](#snake_cmd-gamecpp)
- [useful.js](#usefuljs)
- [black-green.css](#black-greencss)
- [ConsoleIO.cs](#consoleiocs)
_Moved `ffmpeg.md` to ._
----
## [snake_cmd-game.cpp](./snake_cmd-game.cpp)
```text
+---------------+
| +---> |
| +---+ |
| | [F] |
+---------------+
```
A Windows console Snake game which's written in C++
- Compile (with MinGW) → `g++ .\snake_cmd-game.cpp -o .\run`
- Start (in Windows-cmd) → `.\run.exe -t 200 -p`
- Extra flags:
- `-t 100` ← Sets the millisecond delay between each frame/calculation. Default is 200.
- `-p` ← Will enable "portal walls" which makes the snake reappear on the other side instead of game over.
- Other keys and what they do, like `[wasd] move` are on-screen underneath the game.
- The playable field is default 30*30 cells big. Wich is only changeable before compiling.
Scroll [TOP](#random-projects)
## [useful.js](./useful.js)
some useful JavaScript functions
_locate function in `useful.js` for more documentation via JSDoc, like parameter/return description_
- Number
-
see
- String
-
strRem__remove part of a string at a specific index and optionally inserts another string__
string equivalent of `Array.splice`
```typescript
function strSplice(
txt: string,
i: number,
rem: number,
add?: string | undefined
): string
``````javascript
strSplice("Hello#World!", 5, 1); //=> "HelloWorld!"
strSplice("Hello#World!", -7, 1, ", ");//=> "Hello, World!"
strSplice("Hello#World!", 6, -1, ", ");//=> "Hello#, #World!"
```strCharStats__object of how much each character appears in the string__
or for only the given characters
```typescript
function strCharStats(
str: string,
locale?: Intl.LocalesArgument | null,
chars?: string
): Map & Map<"other", number>
``````javascript
strCharStats("abzaacdd"); //~ Map{"other" => 0, "a" => 3, "b" => 1, "z" => 1, "c" => 1, "d" => 2}
strCharStats("abzaacdd", null, "abce");//~ Map{"other" => 3, "a" => 3, "b" => 1, "c" => 1, "e" => 0}
```ansi__Create ANSI codes to set terminal color__
sets output terminal fore/background colors \
! remember to output the reset code before end of script or terminal colors stay this way \
for browser dev-console use `console.log("%cCSS", "background-color: #000; color: #f90");` instead \
! keep in mind that if the terminal doesn't support ansi-codes it will output them as plain text```typescript
function ansi(
c?: number | [number, number, number] | null | undefined,
bg?: number | undefined
): string
``````javascript
console.log("TEST%sTEST%sTEST",ansi(0xff9900),ansi());
// <=> console.log("TEST%cTEST%cTEST","color:#f90","");
```strCompare__get [Damerau-Levenshtein distance](https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance "Wikipedia: Damerau-Levenshtein distance") of two strings__
```typescript
function strCompare(
a: string,
b: string,
locale?: Intl.LocalesArgument | null
): number
``````javascript
strCompare("ca","abc");//=> 2 (flip 'ca' and add 'b')
```strCompareLite__get [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance "Wikipedia: Levenshtein distance") of two strings__
is always greater or equal to `strCompare` (Damerau-Levenshtein distance), but a bit faster for longer strings
```typescript
function strCompareLite(
a: string,
b: string,
locale?: Intl.LocalesArgument | null
): number
``````javascript
strCompareLite("ca","abc");//=> 3 (delete 'c', add 'b', and add 'c')
```performance difference
> node.js `v22.12.0` on intel `i7-10700K`
```text
┌─────────┬────┬────┬────────┬────────┬──────────┬────────────────────────────────────────────────────┐
│ (index) │ A │ B │ Atime │ Btime │ improved │ parameters │
├─────────┼────┼────┼────────┼────────┼──────────┼────────────────────────────────────────────────────┤
│ 0 │ 3 │ 3 │ 0.0465 │ 0.0326 │ '29.89%' │ [ 'sitting', 'kitten' ] │
│ 1 │ 3 │ 3 │ 0.0359 │ 0.0325 │ '9.69%' │ [ 'sunday', 'saturday' ] │
│ 2 │ 1 │ 2 │ 0.0261 │ 0.0244 │ '6.61%' │ [ 'test', 'tset' ] │
│ 3 │ 2 │ 3 │ 0.0211 │ 0.0219 │ '-3.47%' │ [ 'ca', 'abc' ] │
│ 4 │ 0 │ 0 │ 0.0075 │ 0.0075 │ '-0.42%' │ [ 'abc', 'abc' ] │
│ 5 │ 2 │ 2 │ 0.1003 │ 0.0876 │ '12.65%' │ [ 'some more text to...', 'some more text to...' ] │
│ 6 │ 51 │ 52 │ 0.1933 │ 0.1228 │ '36.47%' │ [ 'Lorem ipsum dolor...', 'completely differ...' ] │
│ 7 │ 10 │ 11 │ 0.237 │ 0.1433 │ '39.55%' │ [ 'too sennteces tha...', 'two sentences tha...' ] │
│ 8 │ 4 │ 6 │ 0.162 │ 0.1041 │ '35.75%' │ [ 'two sentneces tha...', 'two sentences tha...' ] │
│ 9 │ 1 │ 1 │ 0.2382 │ 0.1449 │ '39.17%' │ [ 'one difference. L...', 'one difference. L...' ] │
│ 10 │ 1 │ 2 │ 0.2427 │ 0.1501 │ '38.16%' │ [ 'one difference. L...', 'one difference. L...' ] │
└─────────┴────┴────┴────────┴────────┴──────────┴────────────────────────────────────────────────────┘
``````javascript
strCompare("a","b");strCompareLite("a","b");//~ warmup
strCompare("b","c");strCompareLite("b","d");//~ warmup
strCompare("c","d");strCompareLite("c","d");//~ warmup
/**@type {[string,string][]}*/const V=[
["sitting","kitten"],
["sunday","saturday"],
["test","tset"],
["ca","abc"],
["abc","abc"],
["some more text too compare to eachother","some more text to compare to each other"],
["Lorem ipsum dolor sit amet, consectetuer adipiscing elit.","completely different text that may have some characters in common"],
["too sennteces that're long but not all tht muc diffreent to eachothe","two sentences that are long but not all that much different to each other"],
["two sentneces that are long but allmots thet exact same","two sentences that are long but all most the exact same"],
["one difference. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.","one difference. Lorem ipsum door sit amet, consectetuer adipiscing elit."],
["one difference. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.","one difference. Lorem ipsum doolr sit amet, consectetuer adipiscing elit."],
];
console.table(V.map((v,i)=>{
let A,B,a=0,b=0,t;
for(let i=0;i<100;++i){t=performance.now();A=strCompare(v[0],v[1],"en");a+=(performance.now()-t)**-1;}
for(let i=0;i<100;++i){t=performance.now();B=strCompareLite(v[0],v[1],"en");b+=(performance.now()-t)**-1;}
return{
A,B,
Atime:Number((a=100/a).toFixed(4)),
Btime:Number((b=100/b).toFixed(4)),
improved:`${Number((100-b*100/a).toFixed(2))}%`,
parameters:V[i].map(w=>w.length>20?w.substring(0,17)+"...":w)
};
}));
``` - Array
-
hasArrayHoles__checks if the given array has empty slots__
most iterator functions skip empty entries, like `Array.every` and `Array.some`, so they might bypass checks and lead to undefined behavior \
their value is `undefined` but they're treated differently from an actual `undefined` in the array \
but the length attribute does include them since they do contribute to the total length of the arraysee [MDN: Array methods and empty slots](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#array_methods_and_empty_slots "MDN>JavaScript>Array: Array methods and empty slots")
```typescript
function hasArrayHoles(arr: readonly any[]): boolean
``````javascript
hasArrayHoles(["",0,undefined,,,,null,()=>{},[],{}]); //=> true
hasArrayHoles(["",0,undefined,null,()=>{},[],{}]); //=> false
```getArrayHoles__checks if the given array has empty slots__
most iterator functions skip empty entries, like `Array.every` and `Array.some`, so they might bypass checks and lead to undefined behavior \
their value is `undefined` but they're treated differently from an actual `undefined` in the array \
but the length attribute does include them since they do contribute to the total length of the arraysee [MDN: Array methods and empty slots](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#array_methods_and_empty_slots "MDN>JavaScript>Array: Array methods and empty slots")
```typescript
function getArrayHoles(arr: readonly any[]): number[]
``````javascript
getArrayHoles(["",0,undefined,,,,null,()=>{},[],{}]); //=> [3,4,5]
getArrayHoles(["",0,undefined,null,()=>{},[],{}]); //=> []
getArrayHoles([0,1,,,4,,,7,8,9,,11,,]); //=> [2,3,5,6,10,12]
```binarySearch__Binary search in `arr` for `val`__
gives index which keeps `arr` sorted in ascending order \
(use `stable` to get rightmost index for successive equal elements)```typescript
function binarySearch(
arr: ArrayLike,
val: T,
compare?: ((a: T, b: T) => number) | undefined,
stable?: boolean | undefined
): number
``````javascript
let arr = [1, 2, 3, 4, 5];
let i = binarySearch(arr, 3.14);
// i: 3
arr.splice(i, 0, 3.14);
// arr: [1, 2, 3, 3.14, 4, 5]arr = [1, 3, 3, 3, 5];
i = binarySearch(arr, '3', null, false);
// i: 2
arr.splice(i, 0, '3');
// arr: [1, 3, '3', 3, 3, 5]arr = [1, 3, 3, 3, 5];
i = binarySearch(arr, '3', null, true);
// i: 4
arr.splice(i, 0, '3');
// arr: [1, 3, 3, 3, '3', 5]
```getSubarrayOffset__Checks if an array is a slice of another (like `String.indexOf` but for arrays) and gives the index of the first found occurrence__
It does behave similar to `Array.include`, but not `Array.indexOf`/`Array.lastIndexOf`,
as it also uses the [`SameValueZero`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness#same-value-zero_equality "MDN>JavaScript>Equality: Same-value-zero equality")
algorithim for comparisons (by default) and also does not skip [empty slots](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#array_methods_and_empty_slots "MDN>JavaScript>Array: Array methods and empty slots") (read as `undefined`).- `(getSubarrayOffset(arr, [val], false, start) !== -1)` \
gives the same as `arr.includes(val, start)`
- `getSubarrayOffset(arr, [val], false, start, (a, b) => a === b)` \
gives the same as `[...arr].indexOf(val, start)`
- `getSubarrayOffset(arr, [val], true, start, (a, b) => a === b)` \
gives the same as `[...arr].lastIndexOf(val, start)`_Assuming the types are correct, as this throws on type mismatch/index out of range, instead of type coercion, clamp index range, or interpret `{length: 2, 0: 3, 1: 4}` as `[3, 4]`._
```typescript
function getSubarrayOffset<
Tf extends unknown,
Ts extends unknown
>(
full: readonly Tf[],
slice: readonly Ts[],
reverse?: boolean | undefined,
fromIndex?: number | undefined,
equality?: ((a: Tf, b: Ts) => boolean) | undefined
): number```
- Object
-
equal__(recursive) compare two values/objects for equality__
[same value zero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero) & deep scan for objects (prototype & own property descriptors) \
(_functions are only compared by address_)```typescript
function equal(
a: any,
b: any,
valueOnly?: boolean | undefined,
prototype?: boolean | null | undefined
): boolean
``````text
| -- | ← (check propery descriptors)
| vo | ← value only
| -- | ← (same prototype)
| cp | ← check prototype
| ip | ← ignore prototype
┌────────────────────────────────────────────────┬───────┬───────┬───────┬───────┬───────┬───────┐
│ (index) │ -- -- │ vo -- │ -- cp │ vo cp │ -- ip │ vo ip │
├────────────────────────────────────────────────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ string object vs string │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ array object vs array │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ null object vs object prototype │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ objects with different values │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ objects with different properties │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ object vs object with symbol property on array │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │ ❌ │
│ null object vs empty object │ ❌ │ ❌ │ ❌ │ ❌ │ ✔️ │ ✔️ │
│ empty object with equal but not same prototype │ ❌ │ ❌ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │
│ object vs object with frozen value │ ❌ │ ✔️ │ ❌ │ ✔️ │ ❌ │ ✔️ │
│ equal but not same object │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │
│ -0 vs +0 │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │
│ -NaN vs +NaN │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │ ✔️ │
└────────────────────────────────────────────────┴───────┴───────┴───────┴───────┴───────┴───────┘
``````javascript
/**@type {[string,any,any][]}*/
const tests=[
["string object vs string", new String("test"), "test" ], // false
["array object vs array", Object.create(Array.prototype), [] ], // false
["null object vs object prototype", Object.create(null), Object.getPrototypeOf({}) ], // false
["objects with different values", {test:[1,2,3]}, {test:[1,,3]} ], // false
["objects with different properties", {test:[1,2,3]}, {TEST:[1,2,3]} ], // false
["object vs object with symbol property on array",{test:[1,2,3]}, {test:Object.assign([1,2,3],{[Symbol.for("a")]:"a"})}], // false
["null object vs empty object", Object.create(null), {} ], // false ; true for ignore prototype
["empty object with equal but not same prototype",Object.setPrototypeOf({},{test:""}),Object.setPrototypeOf({},{test:""}) ], // false ; true for check prototype & ignore prototype
["object vs object with frozen value", {test:[1,2,3]}, {test:Object.freeze([1,2,3])} ], // false ; true for value only
["equal but not same object", {test:[1,2,3]}, {test:[1,2,3]} ], // true
["-0 vs +0", -0, +0 ], // true
["-NaN vs +NaN", -NaN, +NaN ], // true
];
/**@type {{[test:string]:{[call:string]:any}}}*/
const logTable={};
for(const[test,a,b]of tests)
logTable[test]={
"-- --":equal(a,b,false,null ), // ;
"vo --":equal(a,b,true, null ), // value only ;
"-- cp":equal(a,b,false,true ), // ; check prototype
"vo cp":equal(a,b,true, true ), // value only ; check prototype
"-- ip":equal(a,b,false,false), // ; ignore prototype
"vo ip":equal(a,b,true, false), // value only ; ignore prototype
};
console.table(logTable);
``` - Color
-
HSVtoRGB__convert HSV color to RGB__
! notice that `H` input is in range `[0,6]` so to convert from `[0,360]` (degrees) divide by `60`; or multiply with `6` if coming from `[0,1]` (like `S`/`V` input)
```typescript
function HSVtoRGB(
H: number,
S: number,
V: number
): [number, number, number]
```RGBtoHSV__convert RGB color to HSV__
! notice that hue output is in range `[0,6]` so multiply with `60` to get `[0,360]` (degrees); or divide by `6` for `[0,1]` (like saturation/value output)
```typescript
function RGBtoHSV(
R: number,
G: number,
B: number
): [number, number, number]
```colorHexRound__round hex color from 6/8 digits to 3/4 digits__
rounded componentwise to nearest hex-double like `F5` → `E` = `EE`
```typescript
function colorHexRound(
color: string
): string
```RGBtoCMYK__convert RGB to CMY(K)__
```typescript
function RGBtoCMYK(
R: number,
G: number,
B: number,
excludeK?: boolean | undefined
): [number, number, number, number]
```CMYKtoRGB__convert CMY(K) to RGB__
```typescript
function CMYKtoRGB(
C: number,
M: number,
Y: number,
K?: number | undefined
): [number, number, number]
``` - HTML / DOM
-
getTextDimensions__measures the dimensions of a given `text` in pixels (sub-pixel accurate)__
[!] only works in the context of HTML ie. a browser [!]
for using an elements font use `CSSStyleDeclaration.font` of `window.getComputedStyle` ie `window.getComputedStyle(element, pseudoElementOrNull).font` \
if using `"initial"`, `"revert"`, or any similar or invalid value as font, it seems to use `"10px sans-serif"` (default of `OffscreenCanvasRenderingContext2D.font`)```typescript
function getTextDimensions(
text: string,
fontCSS?: string | undefined
): number
```getMousePos__gets current mouse position (optionally relative to an element)__
[!] only works in the context of HTML ie. a browser [!]
__WARNING__: \
Browsers may use different units for movementX and screenX than what the specification defines. \
The movementX units can be physical, logical, or CSS pixels, depending on the browser and operating system. \
_See [this issue on GitHub](https://github.com/w3c/pointerlock/issues/42) for more information on the topic._```typescript
function getMousePos(
offsetElement?: Element | null | undefined
): [
Readonly<{
page: [number, number];
client: [number, number];
offset: [number, number];
screen: [number, number];
movement: [number, number];
}>,
AbortController
]
``````javascript
const [mousePos, mouseSignal] = getMousePos();
const log = setInterval(() => console.log(JSON.stringify(mousePos)), 1000);
// mouseSignal.abort();
// clearInterval(log);
```styleOverflowFor__Shows gradients at the edges of `el` when it overflows and becommes scrollable__
[!] only works in the context of HTML ie. a browser [!]
Overrides the CSS `background` property (use `background` to add any additional value/s for CSS)
```typescript
function styleOverflowFor(
el: HTMLElement,
offset: number | [number, number],
size: string | [string, string],
color: string,
alphaMax: number,
background?: string | null | undefined
): () => void
``````javascript
const box = document.getElementById("box");
const boxOverflowUpdate = StyleOverflowFor(
box,
0xC8,
[
"clamp(1rem, 5vw, 2rem)",
"clamp(1rem, 5vh, 2rem)"
],
"#CCCC00$x",
2/3,
"#0008"
);
boxOverflowUpdate();
box.addEventListener("scroll", boxOverflowUpdate, {passive: true});
window.addEventListener("resize", boxOverflowUpdate, {passive: true});
``` - Other
-
LoadIMG__fetch image from URL and convert it to (base64) data-URL__
```typescript
LoadIMG.IMG(): (src: string) => Promise
LoadIMG.FetchFileReader(): (src: string) => Promise
LoadIMG.FetchManual(): (src: string) => Promise
``````javascript
// FetchManual and FetchFileReader can also "fetch" other data-URLs and convert them to base64
LoadIMG.FetchManual()("data:text/plain;,Hello, World!").then(console.log);
//=> data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==
//=> Hello, World!// sadly, Unicode is not supported
LoadIMG.FetchManual()("data:text/plain;,test ⣿ unicode ↔ string").then(console.log);
//=> data:text/plain;base64,dGVzdCDio78gdW5pY29kZSDihpQgc3RyaW5n
//=> test ⣿ unicode â string// but for images this doesn't matter
LoadIMG.FetchManual()("https://picsum.photos/id/40/50.webp").then(console.log);
// ↓
``````text
data:image/webp;base64,UklGRqIDAABXRUJQVlA4WAoAAAAIAAAAMQAAMQAAVlA4IKACAABwDgCdASoyADIAPo06lUelIyIhLguIoBGJZQDGOGnpTc74alUQ7JcfLH3CAqEkT5HdCKzmc/LsNcRvnkXL9d9PGgIIdLCND7PXIPXnISPidGgN9vEI84604t47K0wn+Kt2DUHYgLCbQYDR16nTdE8pFKRerZlcgWG19yAAAP7Zux4ZwtVnCo5Dw6Q/Ds87nvXL02B6iSiaT/bRfyuGyiCOCnDImLAv6BcfEOKth2Eipd658UZ9NgvpReW2voVZOkpm2iRdNh3HHlI0Z6MWDOMszRbznpCPWHitNcAQLHYmFyWlu7/psWWar76ChuR3R8N9CR7kTeva2v+//Vk4UCReeaqI5I8TnDeCcr4KLyKrJ52utlg/OlIkWDn1NZWAq+RJTr20EPvB/KiyMJJTkrso2DJPTthuFWkEnBeVRAoQxc/PaHTgzT34LX4orXUPaCFRyAud+aTYJmENUj/qGijXe7qTrBy5zSbowno9GEPNrPG+mi7vLhyszCjC/ajLGGmtwK/ohCw3/yVZQ5H3ms+C8d8P8P3y5EYHyPunL4UVJbC8QwHthDU1FrrE4JzZGuniHBuRDmEqmCx5BJU9ifFIQnHHd5B5Tvn4CKgHETsxpafDqiAwsw6HdFkZdzInd9C02StE6v70dENPlx1/AidSEoZFeWKwsXQNkpbe+0ej5HZxj2XB5qutls4eMY4YuTT26/zwWxcVwMZ5Rr7GPmC3h/B1XRb9i1Sa2Zlb5eVCj3sccFKPHJouE/gs+sLsrXKl4oNKkX4kNkUoLJRV1TLIoguOyhgh7iHLQi23FA0EiF4rwfB0ABYG1U5P0BAAiqSJHoxMsIdcspL7vteYRvvml/tujDFkr8TJBGA3acbJhJcJ9IGwrMBItrMdw8/MAABFWElG3AAAAEV4aWYAAElJKgAIAAAABgASAQMAAQAAAAEAAAAaAQUAAQAAAFYAAAAbAQUAAQAAAF4AAAAoAQMAAQAAAAIAAAATAgMAAQAAAAEAAABphwQAAQAAAGYAAAAAAAAASAAAAAEAAABIAAAAAQAAAAcAAJAHAAQAAAAwMjEwAZEHAAQAAAABAgMAhpIHABUAAADAAAAAAKAHAAQAAAAwMTAwAaADAAEAAAD//wAAAqAEAAEAAAAyAAAAA6AEAAEAAAAyAAAAAAAAAEFTQ0lJAAAAUGljc3VtIElEOiA0MAA=
```> credit
Scroll [UP](#usefuljs) | [TOP](#random-projects)
## [black-green.css](./black-green.css)
some style rules I find useful and nice-looking
Scroll [TOP](#random-projects)
## [ConsoleIO.cs](./ConsoleIO.cs)
A text-based game engine for (windows) console.
It was made for a school project to learn C# with a console game, but as you can see, I went overboard with this.
Features include (but are not limited to)
- changing text color
- moving the cursor and toggle visibility (also save cursor positions to load later)
- writing text horizontally or vertically (auto wraps to window) with optional delay for each character (looks animated)
- writing text can include `'\n'`, `'\r'`, `'\t'` and `'\b'` (also `'\0'` which just delays)
- creating a border with custom characters for all sides and corners
- scrolling the text on the screen (screen buffer), can also be "animated"
- clearing the screen with an animation
- make a noise with given frequency and duration (allways full volume !)
- change window size and toggle fullscreen
- get user imput (type-checked not sanitized)
- pauses the program for given milliseconds
- "press any key"
- custom number formatting
Scroll [TOP](#random-projects)