{"id":24181820,"url":"https://github.com/lbalab/hqr","last_synced_at":"2025-09-21T02:33:14.181Z","repository":{"id":93702363,"uuid":"450642549","full_name":"LBALab/hqr","owner":"LBALab","description":"A javascript HQR reader/writer","archived":false,"fork":false,"pushed_at":"2024-03-29T20:02:03.000Z","size":558,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-12-18T08:07:28.298Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@lbalab/hqr","language":"TypeScript","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/LBALab.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}},"created_at":"2022-01-21T21:17:37.000Z","updated_at":"2022-10-24T08:14:47.000Z","dependencies_parsed_at":"2023-05-09T12:17:14.168Z","dependency_job_id":null,"html_url":"https://github.com/LBALab/hqr","commit_stats":{"total_commits":24,"total_committers":2,"mean_commits":12.0,"dds":0.04166666666666663,"last_synced_commit":"1ec3361283e0efbc8159c633580f538ae3c49e2f"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LBALab%2Fhqr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LBALab%2Fhqr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LBALab%2Fhqr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LBALab%2Fhqr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LBALab","download_url":"https://codeload.github.com/LBALab/hqr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233704833,"owners_count":18717027,"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":"2025-01-13T07:14:22.351Z","updated_at":"2025-09-21T02:33:08.662Z","avatar_url":"https://github.com/LBALab.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HQR Library\n\n[![npm package][npm-img]][npm-url]\n[![Build Status][build-img]][build-url]\n[![Downloads][downloads-img]][downloads-url]\n[![Issues][issues-img]][issues-url]\n[![Code Coverage][codecov-img]][codecov-url]\n[![Commitizen Friendly][commitizen-img]][commitizen-url]\n[![Semantic Release][semantic-release-img]][semantic-release-url]\n\nA javascript HQR reader/writer for node.js and web browsers.\nHQR is a simple file format used by the Little Big Adventure 1 \u0026 2 games for storing data.\n\nA HQR file consists of a header followed by a series of entries which are either compressed or not. It can also contain hidden entries, as a mechanism to store several entries in the same index.\n\nFor more information about the content of the various HQR files found in LBA1 and LBA2 game folders, see [here][lba-file-info-url].\n\n## Install\n\n```bash\nnpm install @lbalab/hqr\n```\n\n## Examples\n\nMake sure to backup your game files before using this library to mess with them.\n\n### Read the palette data:\n\n```js\nconst fs = require('fs/promises');\nconst { HQR } = require('@lbalab/hqr');\n\n(async () =\u003e {\n  const file = await fs.readFile('LBA2/RESS.HQR');\n  const hqr = HQR.fromArrayBuffer(\n    file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength)\n  );\n  console.log(hqr.entries[0].content); // main game palette as an ArrayBuffer\n})();\n```\n\n### Swap HQR entries:\n\n```js\nconst fs = require('fs/promises');\nconst { HQR } = require('@lbalab/hqr');\n\n/*\n ** Swap regular trees with palm trees in citadel island (with rain):\n ** Entry #0: regular tree\n ** Entry #1: palm tree\n */\n(async () =\u003e {\n  const file = await fs.readFile('LBA2/CITADEL.OBL');\n  const hqr = HQR.fromArrayBuffer(\n    file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength)\n  );\n  const tmp = hqr.entries[0];\n  hqr.entries[0] = hqr.entries[4];\n  hqr.entries[4] = tmp;\n  await fs.writeFile('LBA2/CITADEL.OBL', Buffer.from(hqr.toArrayBuffer()));\n})();\n```\n\n### Change an HQR entry's content:\n\n```js\nconst fs = require('fs/promises');\nconst { HQR } = require('@lbalab/hqr');\n\n(async () =\u003e {\n  const file = await fs.readFile('LBA2/TEXT.HQR');\n  const hqr = HQR.fromArrayBuffer(\n    file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength)\n  );\n  const textBank = new Uint8Array(hqr.entries[1].content);\n  /* The string \"Resume Game\" is at offset 943.\n   ** Let's replace the letters e =\u003e é.\n   */\n  textBank[944] = 130;\n  textBank[948] = 130;\n  textBank[953] = 130;\n  fs.writeFile('LBA2/TEXT.HQR', Buffer.from(hqr.toArrayBuffer()));\n})();\n```\n\n### Create an HQR file programmatically:\n\n```js\nconst fs = require('fs/promises');\nconst { HQR, HQREntry, CompressionType } = require('@lbalab/hqr');\n\n/*\n ** This creates a SIMPLE.HQR file from scratch that contains 3 uncompressed entries:\n ** #0: 512 bytes entry filled with 0s\n ** #1: utf-8 string: \"Hello world!\"\n ** #2: 32 bit unsigned integer with value 42 (little endian)\n */\n(async () =\u003e {\n  const hqr = new HQR();\n\n  // Entry #0: 512 bytes filled with 0s\n  hqr.entries.push(new HQREntry(new ArrayBuffer(512), CompressionType.NONE));\n\n  // Entry #1: utf-8 string: \"Hello world!\"\n  const str = 'Hello world!';\n  hqr.entries.push(\n    new HQREntry(Buffer.from(str, 'utf-8'), CompressionType.NONE)\n  );\n\n  // Entry #2: 32 bit unsigned integer with value 42 (little endian)\n  const numView = new DataView(new ArrayBuffer(4));\n  numView.setUint32(0, 42, true);\n  hqr.entries.push(new HQREntry(numView.buffer, CompressionType.NONE));\n\n  await fs.writeFile('SIMPLE.HQR', Buffer.from(hqr.toArrayBuffer()));\n})();\n```\n\n### Show hidden entries information:\n\n```js\nconst fs = require('fs/promises');\nconst { HQR } = require('@lbalab/hqr');\n\n(async () =\u003e {\n  if (process.argv.length \u003c 3) {\n    console.error('Usage: node count-hidden.js \u003cHQR file\u003e');\n    process.exit(1);\n  }\n  const file = await fs.readFile(process.argv[2]);\n  const hqr = HQR.fromArrayBuffer(\n    file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength)\n  );\n  for (let i = 0; i \u003c hqr.entries.length; i++) {\n    const entry = hqr.entries[i];\n    if (!entry) continue;\n\n    console.log(`Entry ${i} has ${entry.hiddenEntries.length} hidden entries:`);\n    let j = 0;\n    for (const hEntry of entry.hiddenEntries) {\n      console.log(`  Hidden entry #${j}: ${hEntry.content.byteLength} bytes`);\n      j++;\n    }\n  }\n})();\n\n/* Example output:\n\n$\u003e node count-hidden.js LBA2/VOX/EN_000.VOX\nEntry 154 has 4 hidden entries:\n  Hidden entry #0: 187692 bytes\n  Hidden entry #1: 156532 bytes\n  Hidden entry #2: 144304 bytes\n  Hidden entry #3: 78528 bytes\nEntry 205 has 1 hidden entries:\n  Hidden entry #0: 139520 bytes\nEntry 232 has 1 hidden entries:\n  Hidden entry #0: 184860 bytes\nEntry 316 has 1 hidden entries:\n  Hidden entry #0: 116344 bytes\n\n**/\n```\n\n## Contributing\n\nCommit format should follow [Angular's commit guidelines][angular-commit-url].\n\n[build-img]: https://github.com/LBALab/hqr/actions/workflows/release.yml/badge.svg\n[build-url]: https://github.com/LBALab/hqr/actions/workflows/release.yml\n[downloads-img]: https://img.shields.io/npm/dt/@lbalab/hqr\n[downloads-url]: https://www.npmtrends.com/@lbalab/hqr\n[npm-img]: https://img.shields.io/npm/v/@lbalab/hqr\n[npm-url]: https://www.npmjs.com/package/@lbalab/hqr\n[issues-img]: https://img.shields.io/github/issues/LBALab/hqr\n[issues-url]: https://github.com/LBALab/hqr/issues\n[codecov-img]: https://codecov.io/gh/LBALab/hqr/branch/main/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/LBALab/hqr\n[semantic-release-img]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\n[semantic-release-url]: https://github.com/semantic-release/semantic-release\n[commitizen-img]: https://img.shields.io/badge/commitizen-friendly-brightgreen.svg\n[commitizen-url]: http://commitizen.github.io/cz-cli/\n[lba-file-info-url]: http://lbafileinfo.kaziq.net/index.php/Main_Page\n[angular-commit-url]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbalab%2Fhqr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flbalab%2Fhqr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbalab%2Fhqr/lists"}