{"id":23503451,"url":"https://github.com/rblsb/kharec","last_synced_at":"2026-01-29T22:31:32.058Z","repository":{"id":128253342,"uuid":"199285015","full_name":"RblSb/KhaRec","owner":"RblSb","description":"Simple g2 command recorder","archived":false,"fork":false,"pushed_at":"2019-07-28T16:16:56.000Z","size":14,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-16T17:56:12.488Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Haxe","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RblSb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2019-07-28T12:34:14.000Z","updated_at":"2020-03-24T23:52:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"265311b5-cdc9-4094-989d-5f9f9397337e","html_url":"https://github.com/RblSb/KhaRec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RblSb%2FKhaRec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RblSb%2FKhaRec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RblSb%2FKhaRec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RblSb%2FKhaRec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RblSb","download_url":"https://codeload.github.com/RblSb/KhaRec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252531880,"owners_count":21763293,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-12-25T08:29:47.249Z","updated_at":"2026-01-29T22:31:32.018Z","avatar_url":"https://github.com/RblSb.png","language":"Haxe","funding_links":[],"categories":[],"sub_categories":[],"readme":"## KhaRec\n\nSimple way to write graphics2 commands to file and play it.\nOnly for fun, html5 and g2 on g4.\n\n### Implementation details\n\n`Graphics2` is shadowed with almost same code, but has `Recorder.drawImage(img, x, y)` call in `drawImage` function, same for other commands from `rec.Command` (no font/drawString currently). `Recorder` does nothing if not activated in user code. After activation it start writing some commands into `FastFloat` array and then saves it to a file with compression. `Player` just reads that array and run a record in the loop.\n\n### Usage\n\nFirst of all, add [pako.min.js](https://raw.githubusercontent.com/hamaluik/haxe-pako/master/libs/pako.min.js) to `Assets` and to [index.html](https://github.com/Kode/Kha/wiki/HTML5#custom-indexhtml-and-js-libraries). 30s 60fps record with pako compression can have 900 kb size for one million graphic commands. Don't ask how fat it can be without compression.\n\nLets add code in game for Recorder/Player activation in `onKeyDown` event:\n```haxe\nif (key == Zero) {\n\t// Start/Stop recording on `0` key\n\tif (!rec.Recorder.isActive) rec.Recorder.enable();\n\telse rec.Recorder.save();\n\treturn;\n}\nif (key == Nine) {\n\t// Start/Stop playing from file on `9` key\n\t// Recorder writes all renderTargets as one image,\n\t// so it supports only one renderTarget\n\t// We can send it to Player\n\tif (!rec.Player.isActive) rec.Player.enable(optionalAtlasImage);\n\telse rec.Player.disable();\n\treturn;\n}\n```\nCode for `Player` in render loop:\n```haxe\nif (rec.Player.isActive) {\n\trec.Player.render(framebuffer.g2);\n\treturn;\n}\n```\nAnd code for `Recorder` in render loop:\n```haxe\nfinal g = framebuffer.g2;\nrec.Recorder.frameBegin(g);\n// actual render code\n// g.begin();\n// ...\n// g.end();\nrec.Recorder.frameEnd();\n```\nThat's all folks! Beware, `Recorder` writes image ids to data array, so any new image in `Assets` will break recordings. Can be avoided with `ImageName =\u003e IntId` map in data file, but this is just concept, feel free to hack or contribute.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frblsb%2Fkharec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frblsb%2Fkharec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frblsb%2Fkharec/lists"}