{"id":18400114,"url":"https://github.com/maz01001/other-projects","last_synced_at":"2026-06-23T03:31:38.699Z","repository":{"id":50725722,"uuid":"364313186","full_name":"MAZ01001/other-projects","owner":"MAZ01001","description":"other small projects not hosted on my GitHub-page","archived":false,"fork":false,"pushed_at":"2026-03-17T10:21:08.000Z","size":208,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-18T01:26:31.144Z","etag":null,"topics":["ascii-game","cmd","cpp","game","games","snake-game"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MAZ01001.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-05-04T16:06:48.000Z","updated_at":"2026-03-17T10:21:12.000Z","dependencies_parsed_at":"2024-12-24T11:33:45.985Z","dependency_job_id":"919ff279-09a7-44cb-b077-828c6f5be0c4","html_url":"https://github.com/MAZ01001/other-projects","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MAZ01001/other-projects","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAZ01001%2Fother-projects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAZ01001%2Fother-projects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAZ01001%2Fother-projects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAZ01001%2Fother-projects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MAZ01001","download_url":"https://codeload.github.com/MAZ01001/other-projects/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAZ01001%2Fother-projects/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34674702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ascii-game","cmd","cpp","game","games","snake-game"],"created_at":"2024-11-06T02:29:53.085Z","updated_at":"2026-06-23T03:31:38.693Z","avatar_url":"https://github.com/MAZ01001.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Random projects\n\nOther _small_ projects that don't have their own repo (yet?)\nor aren't strongly related to [Math-JS](https://github.com/MAZ01001/Math-Js \"My Math-js repo\")\n\nalso...other languages than javascript ?! :o\n\n- [snake_cmd-game.cpp](#snake_cmd-gamecpp)\n- [useful.js](#usefuljs)\n- [black-green.css](#black-greencss)\n- [ConsoleIO.cs](#consoleiocs)\n\n_Moved `ffmpeg.md` to \u003chttps://github.com/MAZ01001/FFmpeg-resource\u003e._\n\n----\n\n## [snake_cmd-game.cpp](./snake_cmd-game.cpp)\n\n```text\n+---------------+\n|       +---\u003e   |\n|   +---+       |\n|   |      [F]  |\n+---------------+\n```\n\nA Windows console Snake game which's written in C++\n\n- Compile (with MinGW) → `g++ .\\snake_cmd-game.cpp -o .\\run`\n- Start (in Windows-cmd) → `.\\run.exe -t 200 -p`\n  - Extra flags:\n    - `-t 100` ← Sets the millisecond delay between each frame/calculation. Default is 200.\n    - `-p` ← Will enable \"portal walls\" which makes the snake reappear on the other side instead of game over.\n  - Other keys and what they do, like `[wasd] move` are on-screen underneath the game.\n  - The playable field is default 30*30 cells big. Wich is only changeable before compiling.\n\nScroll [TOP](#random-projects)\n\n## [useful.js](./useful.js)\n\nsome useful JavaScript functions\n\n_locate function in `useful.js` for more documentation via JSDoc, like parameter/return description_\n\n\u003cdl\u003e\n\u003cdt\u003eNumber\u003c/dt\u003e\n\u003cdd\u003e\n\nsee \u003chttps://github.com/MAZ01001/Math-Js#functionsjs\u003e\n\n\u003c/dd\u003e\n\u003cdt\u003eString\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003estrRem\u003c/code\u003e\u003c/summary\u003e\n\n__remove part of a string at a specific index and optionally inserts another string__\n\nstring equivalent of `Array.splice`\n\n```typescript\nfunction strSplice(\n    txt: string,\n    i: number,\n    rem: number,\n    add?: string | undefined\n): string\n```\n\n```javascript\nstrSplice(\"Hello#World!\",  5,  1);      //=\u003e \"HelloWorld!\"\nstrSplice(\"Hello#World!\", -7,  1, \", \");//=\u003e \"Hello, World!\"\nstrSplice(\"Hello#World!\",  6, -1, \", \");//=\u003e \"Hello#, #World!\"\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003estrCharStats\u003c/code\u003e\u003c/summary\u003e\n\n__object of how much each character appears in the string__\n\nor for only the given characters\n\n```typescript\nfunction strCharStats(\n    str: string,\n    locale?: Intl.LocalesArgument | null,\n    chars?: string\n): Map\u003cstring, number\u003e \u0026 Map\u003c\"other\", number\u003e\n```\n\n```javascript\nstrCharStats(\"abzaacdd\");              //~ Map{\"other\" =\u003e 0, \"a\" =\u003e 3, \"b\" =\u003e 1, \"z\" =\u003e 1, \"c\" =\u003e 1, \"d\" =\u003e 2}\nstrCharStats(\"abzaacdd\", null, \"abce\");//~ Map{\"other\" =\u003e 3, \"a\" =\u003e 3, \"b\" =\u003e 1, \"c\" =\u003e 1, \"e\" =\u003e 0}\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eansi\u003c/code\u003e\u003c/summary\u003e\n\n__Create ANSI codes to set terminal color__\n\nsets output terminal fore/background colors \\\n! remember to output the reset code before end of script or terminal colors stay this way \\\nfor browser dev-console use `console.log(\"%cCSS\", \"background-color: #000; color: #f90\");` instead \\\n! keep in mind that if the terminal doesn't support ansi-codes it will output them as plain text\n\n```typescript\nfunction ansi(\n    c?: number | [number, number, number] | null | undefined,\n    bg?: number | undefined\n): string\n```\n\n```javascript\nconsole.log(\"TEST%sTEST%sTEST\",ansi(0xff9900),ansi());\n// \u003c=\u003e console.log(\"TEST%cTEST%cTEST\",\"color:#f90\",\"\");\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003estrCompare\u003c/code\u003e\u003c/summary\u003e\n\n__get [Damerau-Levenshtein distance](https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance \"Wikipedia: Damerau-Levenshtein distance\") of two strings__\n\n```typescript\nfunction strCompare(\n    a: string,\n    b: string,\n    locale?: Intl.LocalesArgument | null\n): number\n```\n\n```javascript\nstrCompare(\"ca\",\"abc\");//=\u003e 2 (flip 'ca' and add 'b')\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003estrCompareLite\u003c/code\u003e\u003c/summary\u003e\n\n__get [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance \"Wikipedia: Levenshtein distance\") of two strings__\n\nis always greater or equal to `strCompare` (Damerau-Levenshtein distance), but a bit faster for longer strings\n\n```typescript\nfunction strCompareLite(\n    a: string,\n    b: string,\n    locale?: Intl.LocalesArgument | null\n): number\n```\n\n```javascript\nstrCompareLite(\"ca\",\"abc\");//=\u003e 3 (delete 'c', add 'b', and add 'c')\n```\n\n\u003cdetails\u003e\u003csummary\u003eperformance difference\u003c/summary\u003e\n\n\u003e node.js `v22.12.0` on intel `i7-10700K`\n\n```text\n┌─────────┬────┬────┬────────┬────────┬──────────┬────────────────────────────────────────────────────┐\n│ (index) │ A  │ B  │ Atime  │ Btime  │ improved │ parameters                                         │\n├─────────┼────┼────┼────────┼────────┼──────────┼────────────────────────────────────────────────────┤\n│ 0       │ 3  │ 3  │ 0.0465 │ 0.0326 │ '29.89%' │ [ 'sitting', 'kitten' ]                            │\n│ 1       │ 3  │ 3  │ 0.0359 │ 0.0325 │ '9.69%'  │ [ 'sunday', 'saturday' ]                           │\n│ 2       │ 1  │ 2  │ 0.0261 │ 0.0244 │ '6.61%'  │ [ 'test', 'tset' ]                                 │\n│ 3       │ 2  │ 3  │ 0.0211 │ 0.0219 │ '-3.47%' │ [ 'ca', 'abc' ]                                    │\n│ 4       │ 0  │ 0  │ 0.0075 │ 0.0075 │ '-0.42%' │ [ 'abc', 'abc' ]                                   │\n│ 5       │ 2  │ 2  │ 0.1003 │ 0.0876 │ '12.65%' │ [ 'some more text to...', 'some more text to...' ] │\n│ 6       │ 51 │ 52 │ 0.1933 │ 0.1228 │ '36.47%' │ [ 'Lorem ipsum dolor...', 'completely differ...' ] │\n│ 7       │ 10 │ 11 │ 0.237  │ 0.1433 │ '39.55%' │ [ 'too sennteces tha...', 'two sentences tha...' ] │\n│ 8       │ 4  │ 6  │ 0.162  │ 0.1041 │ '35.75%' │ [ 'two sentneces tha...', 'two sentences tha...' ] │\n│ 9       │ 1  │ 1  │ 0.2382 │ 0.1449 │ '39.17%' │ [ 'one difference. L...', 'one difference. L...' ] │\n│ 10      │ 1  │ 2  │ 0.2427 │ 0.1501 │ '38.16%' │ [ 'one difference. L...', 'one difference. L...' ] │\n└─────────┴────┴────┴────────┴────────┴──────────┴────────────────────────────────────────────────────┘\n```\n\n```javascript\nstrCompare(\"a\",\"b\");strCompareLite(\"a\",\"b\");//~ warmup\nstrCompare(\"b\",\"c\");strCompareLite(\"b\",\"d\");//~ warmup\nstrCompare(\"c\",\"d\");strCompareLite(\"c\",\"d\");//~ warmup\n/**@type {[string,string][]}*/const V=[\n    [\"sitting\",\"kitten\"],\n    [\"sunday\",\"saturday\"],\n    [\"test\",\"tset\"],\n    [\"ca\",\"abc\"],\n    [\"abc\",\"abc\"],\n    [\"some more text too compare to eachother\",\"some more text to compare to each other\"],\n    [\"Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\",\"completely different text that may have some characters in common\"],\n    [\"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\"],\n    [\"two sentneces that are long but allmots thet exact same\",\"two sentences that are long but all most the exact same\"],\n    [\"one difference. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\",\"one difference. Lorem ipsum door sit amet, consectetuer adipiscing elit.\"],\n    [\"one difference. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\",\"one difference. Lorem ipsum doolr sit amet, consectetuer adipiscing elit.\"],\n];\nconsole.table(V.map((v,i)=\u003e{\n    let A,B,a=0,b=0,t;\n    for(let i=0;i\u003c100;++i){t=performance.now();A=strCompare(v[0],v[1],\"en\");a+=(performance.now()-t)**-1;}\n    for(let i=0;i\u003c100;++i){t=performance.now();B=strCompareLite(v[0],v[1],\"en\");b+=(performance.now()-t)**-1;}\n    return{\n        A,B,\n        Atime:Number((a=100/a).toFixed(4)),\n        Btime:Number((b=100/b).toFixed(4)),\n        improved:`${Number((100-b*100/a).toFixed(2))}%`,\n        parameters:V[i].map(w=\u003ew.length\u003e20?w.substring(0,17)+\"...\":w)\n    };\n}));\n```\n\n\u003c/details\u003e\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003cdt\u003eArray\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003ehasArrayHoles\u003c/code\u003e\u003c/summary\u003e\n\n__checks if the given array has empty slots__\n\nmost iterator functions skip empty entries, like `Array.every` and `Array.some`, so they might bypass checks and lead to undefined behavior \\\ntheir value is `undefined` but they're treated differently from an actual `undefined` in the array \\\nbut the length attribute does include them since they do contribute to the total length of the array\n\nsee [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\u003eJavaScript\u003eArray: Array methods and empty slots\")\n\n```typescript\nfunction hasArrayHoles(arr: readonly any[]): boolean\n```\n\n```javascript\nhasArrayHoles([\"\",0,undefined,,,,null,()=\u003e{},[],{}]); //=\u003e true\nhasArrayHoles([\"\",0,undefined,null,()=\u003e{},[],{}]);    //=\u003e false\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003egetArrayHoles\u003c/code\u003e\u003c/summary\u003e\n\n__checks if the given array has empty slots__\n\nmost iterator functions skip empty entries, like `Array.every` and `Array.some`, so they might bypass checks and lead to undefined behavior \\\ntheir value is `undefined` but they're treated differently from an actual `undefined` in the array \\\nbut the length attribute does include them since they do contribute to the total length of the array\n\nsee [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\u003eJavaScript\u003eArray: Array methods and empty slots\")\n\n```typescript\nfunction getArrayHoles(arr: readonly any[]): number[]\n```\n\n```javascript\ngetArrayHoles([\"\",0,undefined,,,,null,()=\u003e{},[],{}]); //=\u003e [3,4,5]\ngetArrayHoles([\"\",0,undefined,null,()=\u003e{},[],{}]);    //=\u003e []\ngetArrayHoles([0,1,,,4,,,7,8,9,,11,,]);               //=\u003e [2,3,5,6,10,12]\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003ebinarySearch\u003c/code\u003e\u003c/summary\u003e\n\n__Binary search in `arr` for `val`__\n\ngives index which keeps `arr` sorted in ascending order \\\n(use `stable` to get rightmost index for successive equal elements)\n\n```typescript\nfunction binarySearch\u003cT\u003e(\n    arr: ArrayLike\u003cT\u003e,\n    val: T,\n    compare?: ((a: T, b: T) =\u003e number) | undefined,\n    stable?: boolean | undefined\n): number\n```\n\n```javascript\nlet arr = [1, 2, 3, 4, 5];\nlet i = binarySearch(arr, 3.14);\n// i: 3\narr.splice(i, 0, 3.14);\n// arr: [1, 2, 3, 3.14, 4, 5]\n\narr = [1, 3, 3, 3, 5];\ni = binarySearch(arr, '3', null, false);\n// i: 2\narr.splice(i, 0, '3');\n// arr: [1, 3, '3', 3, 3, 5]\n\narr = [1, 3, 3, 3, 5];\ni = binarySearch(arr, '3', null, true);\n// i: 4\narr.splice(i, 0, '3');\n// arr: [1, 3, 3, 3, '3', 5]\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003egetSubarrayOffset\u003c/code\u003e\u003c/summary\u003e\n\n__Checks if an array is a slice of another (like `String.indexOf` but for arrays) and gives the index of the first found occurrence__\n\nIt does behave similar to `Array.include`, but not `Array.indexOf`/`Array.lastIndexOf`,\nas it also uses the [`SameValueZero`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness#same-value-zero_equality \"MDN\u003eJavaScript\u003eEquality: Same-value-zero equality\")\nalgorithim 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\u003eJavaScript\u003eArray: Array methods and empty slots\") (read as `undefined`).\n\n- `(getSubarrayOffset(arr, [val], false, start) !== -1)` \\\n  gives the same as `arr.includes(val, start)`\n- `getSubarrayOffset(arr, [val], false, start, (a, b) =\u003e a === b)` \\\n  gives the same as `[...arr].indexOf(val, start)`\n- `getSubarrayOffset(arr, [val], true, start, (a, b) =\u003e a === b)` \\\n  gives the same as `[...arr].lastIndexOf(val, start)`\n\n_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]`._\n\n```typescript\nfunction getSubarrayOffset\u003c\n    Tf extends unknown,\n    Ts extends unknown\n\u003e(\n    full: readonly Tf[],\n    slice: readonly Ts[],\n    reverse?: boolean | undefined,\n    fromIndex?: number | undefined,\n    equality?: ((a: Tf, b: Ts) =\u003e boolean) | undefined\n): number\n\n```\n\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003cdt\u003eObject\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eequal\u003c/code\u003e\u003c/summary\u003e\n\n__(recursive) compare two values/objects for equality__\n\n[same value zero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero) \u0026 deep scan for objects (prototype \u0026 own property descriptors) \\\n(_functions are only compared by address_)\n\n```typescript\nfunction equal(\n    a: any,\n    b: any,\n    valueOnly?: boolean | undefined,\n    prototype?: boolean | null | undefined\n): boolean\n```\n\n```text\n| --    | ← (check propery descriptors)\n| vo    | ← value only\n|    -- | ← (same prototype)\n|    cp | ← check prototype\n|    ip | ← ignore prototype\n┌────────────────────────────────────────────────┬───────┬───────┬───────┬───────┬───────┬───────┐\n│ (index)                                        │ -- -- │ vo -- │ -- cp │ vo cp │ -- ip │ vo ip │\n├────────────────────────────────────────────────┼───────┼───────┼───────┼───────┼───────┼───────┤\n│ string object vs string                        │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ array object vs array                          │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ null object vs object prototype                │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ objects with different values                  │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ objects with different properties              │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ object vs object with symbol property on array │  ❌  │   ❌  │  ❌  │   ❌  │  ❌  │   ❌  │\n│ null object vs empty object                    │  ❌  │   ❌  │  ❌  │   ❌  │  ✔️  │   ✔️  │\n│ empty object with equal but not same prototype │  ❌  │   ❌  │  ✔️  │   ✔️  │  ✔️  │   ✔️  │\n│ object vs object with frozen value             │  ❌  │   ✔️  │  ❌  │   ✔️  │  ❌  │   ✔️  │\n│ equal but not same object                      │  ✔️  │   ✔️  │  ✔️  │   ✔️  │  ✔️  │   ✔️  │\n│ -0 vs +0                                       │  ✔️  │   ✔️  │  ✔️  │   ✔️  │  ✔️  │   ✔️  │\n│ -NaN vs +NaN                                   │  ✔️  │   ✔️  │  ✔️  │   ✔️  │  ✔️  │   ✔️  │\n└────────────────────────────────────────────────┴───────┴───────┴───────┴───────┴───────┴───────┘\n```\n\n```javascript\n/**@type {[string,any,any][]}*/\nconst tests=[\n    [\"string object vs string\",                       new String(\"test\"),                 \"test\"                                               ], // false\n    [\"array object vs array\",                         Object.create(Array.prototype),     []                                                   ], // false\n    [\"null object vs object prototype\",               Object.create(null),                Object.getPrototypeOf({})                            ], // false\n    [\"objects with different values\",                 {test:[1,2,3]},                     {test:[1,,3]}                                        ], // false\n    [\"objects with different properties\",             {test:[1,2,3]},                     {TEST:[1,2,3]}                                       ], // false\n    [\"object vs object with symbol property on array\",{test:[1,2,3]},                     {test:Object.assign([1,2,3],{[Symbol.for(\"a\")]:\"a\"})}], // false\n    [\"null object vs empty object\",                   Object.create(null),                {}                                                   ], // false ; true for ignore prototype\n    [\"empty object with equal but not same prototype\",Object.setPrototypeOf({},{test:\"\"}),Object.setPrototypeOf({},{test:\"\"})                  ], // false ; true for check prototype \u0026 ignore prototype\n    [\"object vs object with frozen value\",            {test:[1,2,3]},                     {test:Object.freeze([1,2,3])}                        ], // false ; true for value only\n    [\"equal but not same object\",                     {test:[1,2,3]},                     {test:[1,2,3]}                                       ], // true\n    [\"-0 vs +0\",                                      -0,                                 +0                                                   ], // true\n    [\"-NaN vs +NaN\",                                  -NaN,                               +NaN                                                 ], // true\n];\n/**@type {{[test:string]:{[call:string]:any}}}*/\nconst logTable={};\nfor(const[test,a,b]of tests)\n    logTable[test]={\n        \"-- --\":equal(a,b,false,null ), //            ;\n        \"vo --\":equal(a,b,true, null ), // value only ;\n        \"-- cp\":equal(a,b,false,true ), //            ; check prototype\n        \"vo cp\":equal(a,b,true, true ), // value only ; check prototype\n        \"-- ip\":equal(a,b,false,false), //            ; ignore prototype\n        \"vo ip\":equal(a,b,true, false), // value only ; ignore prototype\n    };\nconsole.table(logTable);\n```\n\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003cdt\u003eColor\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eHSVtoRGB\u003c/code\u003e\u003c/summary\u003e\n\n__convert HSV color to RGB__\n\n! 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)\n\n```typescript\nfunction HSVtoRGB(\n    H: number,\n    S: number,\n    V: number\n): [number, number, number]\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eRGBtoHSV\u003c/code\u003e\u003c/summary\u003e\n\n__convert RGB color to HSV__\n\n! 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)\n\n```typescript\nfunction RGBtoHSV(\n    R: number,\n    G: number,\n    B: number\n): [number, number, number]\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003ecolorHexRound\u003c/code\u003e\u003c/summary\u003e\n\n__round hex color from 6/8 digits to 3/4 digits__\n\nrounded componentwise to nearest hex-double like `F5` → `E` = `EE`\n\n```typescript\nfunction colorHexRound(\n    color: string\n): string\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eRGBtoCMYK\u003c/code\u003e\u003c/summary\u003e\n\n__convert RGB to CMY(K)__\n\n```typescript\nfunction RGBtoCMYK(\n    R: number,\n    G: number,\n    B: number,\n    excludeK?: boolean | undefined\n): [number, number, number, number]\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eCMYKtoRGB\u003c/code\u003e\u003c/summary\u003e\n\n__convert CMY(K) to RGB__\n\n```typescript\nfunction CMYKtoRGB(\n    C: number,\n    M: number,\n    Y: number,\n    K?: number | undefined\n): [number, number, number]\n```\n\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003cdt\u003eHTML / DOM\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003egetTextDimensions\u003c/code\u003e\u003c/summary\u003e\n\n__measures the dimensions of a given `text` in pixels (sub-pixel accurate)__\n\n[!] only works in the context of HTML ie. a browser [!]\n\nfor using an elements font use `CSSStyleDeclaration.font` of `window.getComputedStyle` ie `window.getComputedStyle(element, pseudoElementOrNull).font` \\\nif using `\"initial\"`, `\"revert\"`, or any similar or invalid value as font, it seems to use `\"10px sans-serif\"` (default of `OffscreenCanvasRenderingContext2D.font`)\n\n```typescript\nfunction getTextDimensions(\n    text: string,\n    fontCSS?: string | undefined\n): number\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003egetMousePos\u003c/code\u003e\u003c/summary\u003e\n\n__gets current mouse position (optionally relative to an element)__\n\n[!] only works in the context of HTML ie. a browser [!]\n\n__WARNING__: \\\nBrowsers may use different units for movementX and screenX than what the specification defines. \\\nThe movementX units can be physical, logical, or CSS pixels, depending on the browser and operating system. \\\n_See [this issue on GitHub](https://github.com/w3c/pointerlock/issues/42) for more information on the topic._\n\n```typescript\nfunction getMousePos(\n    offsetElement?: Element | null | undefined\n): [\n    Readonly\u003c{\n        page: [number, number];\n        client: [number, number];\n        offset: [number, number];\n        screen: [number, number];\n        movement: [number, number];\n    }\u003e,\n    AbortController\n]\n```\n\n```javascript\nconst [mousePos, mouseSignal] = getMousePos();\nconst log = setInterval(() =\u003e console.log(JSON.stringify(mousePos)), 1000);\n// mouseSignal.abort();\n// clearInterval(log);\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003estyleOverflowFor\u003c/code\u003e\u003c/summary\u003e\n\n__Shows gradients at the edges of `el` when it overflows and becommes scrollable__\n\n[!] only works in the context of HTML ie. a browser [!]\n\nOverrides the CSS `background` property (use `background` to add any additional value/s for CSS)\n\n```typescript\nfunction styleOverflowFor(\n    el: HTMLElement,\n    offset: number | [number, number],\n    size: string | [string, string],\n    color: string,\n    alphaMax: number,\n    background?: string | null | undefined\n): () =\u003e void\n```\n\n```javascript\nconst box = document.getElementById(\"box\");\nconst boxOverflowUpdate = StyleOverflowFor(\n    box,\n    0xC8,\n    [\n        \"clamp(1rem, 5vw, 2rem)\",\n        \"clamp(1rem, 5vh, 2rem)\"\n    ],\n    \"#CCCC00$x\",\n    2/3,\n    \"#0008\"\n);\nboxOverflowUpdate();\nbox.addEventListener(\"scroll\", boxOverflowUpdate, {passive: true});\nwindow.addEventListener(\"resize\", boxOverflowUpdate, {passive: true});\n```\n\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003cdt\u003eOther\u003c/dt\u003e\n\u003cdd\u003e\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eLoadIMG\u003c/code\u003e\u003c/summary\u003e\n\n__fetch image from URL and convert it to (base64) data-URL__\n\n```typescript\nLoadIMG.IMG():             (src: string) =\u003e Promise\u003cstring | null\u003e\nLoadIMG.FetchFileReader(): (src: string) =\u003e Promise\u003cstring | null\u003e\nLoadIMG.FetchManual():     (src: string) =\u003e Promise\u003cstring | null\u003e\n```\n\n```javascript\n// FetchManual and FetchFileReader can also \"fetch\" other data-URLs and convert them to base64\nLoadIMG.FetchManual()(\"data:text/plain;,Hello, World!\").then(console.log);\n//=\u003e data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==\n//=\u003e Hello, World!\n\n// sadly, Unicode is not supported\nLoadIMG.FetchManual()(\"data:text/plain;,test ⣿ unicode ↔ string\").then(console.log);\n//=\u003e data:text/plain;base64,dGVzdCDio78gdW5pY29kZSDihpQgc3RyaW5n\n//=\u003e test â£¿ unicode â string\n\n// but for images this doesn't matter\nLoadIMG.FetchManual()(\"https://picsum.photos/id/40/50.webp\").then(console.log);\n// ↓\n```\n\n```text\ndata: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=\n```\n\n\u003e credit \u003chttps://picsum.photos/id/40/info\u003e\n\n\u003c/details\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\nScroll [UP](#usefuljs) | [TOP](#random-projects)\n\n## [black-green.css](./black-green.css)\n\nsome style rules I find useful and nice-looking\n\nScroll [TOP](#random-projects)\n\n## [ConsoleIO.cs](./ConsoleIO.cs)\n\nA text-based game engine for (windows) console.\n\nIt was made for a school project to learn C# with a console game, but as you can see, I went overboard with this.\n\nFeatures include (but are not limited to)\n\n- changing text color\n- moving the cursor and toggle visibility (also save cursor positions to load later)\n- writing text horizontally or vertically (auto wraps to window) with optional delay for each character (looks animated)\n- writing text can include `'\\n'`, `'\\r'`, `'\\t'` and `'\\b'` (also `'\\0'` which just delays)\n- creating a border with custom characters for all sides and corners\n- scrolling the text on the screen (screen buffer), can also be \"animated\"\n- clearing the screen with an animation\n- make a noise with given frequency and duration (allways full volume !)\n- change window size and toggle fullscreen\n- get user imput (type-checked not sanitized)\n- pauses the program for given milliseconds\n- \"press any key\"\n- custom number formatting\n\nScroll [TOP](#random-projects)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaz01001%2Fother-projects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaz01001%2Fother-projects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaz01001%2Fother-projects/lists"}