TWINPACK file format

Warning

This binary format is an internal implementation detail of the twinBASIC IDE and is subject to change without notice. There is no official support for reading or writing these files outside of the twinBASIC executable. If you build tooling that relies on this format, be prepared for breakage when the IDE is updated.

Both .twinproj (project files) and .twinpack (distributable package files) use the same binary container format. The format encodes a tree of named entries — directories containing children, and files containing binary content.

All multi-byte integers are little-endian.

File header

Every file begins with a 4-byte magic number:

Offset Size Type Value Description
0x00 4 uint32 0xEA0BA51C Magic number (constant).

The root entry immediately follows the magic.

Primitive types

LenString

A length-prefixed byte string. Encoding is UTF-8 for filenames and text content; binary content (images, etc.) is stored verbatim.

Offset Size Type Description
+0 4 uint32 length — byte count. May be 0.
+4 length byte[] Raw bytes. Absent when length is 0.

Entry structure

Every node in the tree — the root, directories, and files — shares the same common header. The first 2 bytes carry one of two meanings depending on position: at the root entry they hold the file format version; everywhere else they hold the entry kind.

Offset Size Type Field Description
+0 2 int16 kind At the root: file format version (currently 1). Everywhere else: entry kind (1 = file, 2 = directory).
+2 var LenString name Entry name (filename or folder name).
+2+var 8 uint64 revision Revision counter (see revision).
4 uint32 flags File-system flags bitmask (see flags).
1 uint8 category Category tag (see category).

After this common header, the entry body depends on whether the entry is a file or a directory.

Determining entry type

The root entry is always the first entry parsed. It is always a directory — its 2-byte field is the file format version, not a kind tag, and its value (currently 1) coincides with the file-kind value but should not be read as one. Every entry after the root is determined by its kind:

  • Filekind == 1. Body: content blob followed by a revision trailer.
  • Directorykind == 2. Body: child count followed by child entries.

Directory body

Follows the common header for directory entries:

Offset Size Type Field Description
+0 4 uint32 count Number of child entries. May be 0.
+4 var Entry[] children count child entries, concatenated.

File body

Follows the common header for file entries:

Offset Size Type Field Description
+0 var LenString contents File content (source code, images, JSON, etc.).
+var 4 uint32 revisionCount Number of trailing revision entries.
+var+4 revisionCount×4 uint32[] revisions Revision entries. Absent when revisionCount is 0.

The revisionCount field is 0 for the vast majority of files, making the file body effectively just the contents followed by 4 zero bytes. Non-zero counts have been observed in packages that embed other packages.

Field details

revision counter

For files, revision is a 64-bit counter that starts at a low value and increments with each edit inside the IDE. For the root entry and directories it is always 0.

Context Typical values
New or untouched file 0x00020x0009
Heavily edited file 0x17D5, 0x1AA0
Root and directories 0x0000

Only the low 16 bits have been observed to vary in real-world files; the upper 48 bits are always zero in practice.

flags

A 32-bit bitmask describing file-system-level properties of the entry. Every entry observed so far has flags == 0, but the IDE recognises the following bits:

Bit value Name Meaning
0x00000000 None Default — no flags set.
0x00000001 Hidden Hidden from the user, but accessible via the VFS.
0x00000002 SuperHidden Not accessible via the VFS — internal only.
0x00000004 Virtual Virtual items are skipped during serialization.

Other bits are reserved.

category tag

Encodes the semantic role of the entry within the project:

category Entry name Meaning
0x00 (various) Default. Used for the root, most files, and resource subdirectories (BITMAP, ICON, MANIFEST).
0x01 References References directory. Always virtual — see note below.
0x02 Resources Resource directory.
0x03 Sources Source code directory.
0x04 Settings Project settings file (JSON).
0x05 ImportedTypeLibraries Imported type library directory.
0x06 Miscellaneous Miscellaneous files directory (screenshots, etc.).
0x07 Packages Package references directory.

Note

The References directory (category 0x01) is a virtual folder — it carries the Virtual flag and is skipped during serialization, so it never appears in saved .twinproj or .twinpack files. The IDE materialises it at runtime from the project’s references list.

Differences between .twinproj and .twinpack

Both formats use the identical binary structure. The differences are in which entries are present:

Entry .twinproj .twinpack
.meta file Yes No
CHANGELOG.md Sometimes Sometimes
LICENCE.md Sometimes Sometimes
Settings file Yes Yes
Sources directory Yes Yes
Resources directory Yes Yes
Packages directory Yes Yes

The References directory (category 0x01) is virtual and is omitted from both formats during serialization — see category tag.

.meta file

Present only in .twinproj files. Contains JSON storing the user’s IDE layout preferences — expanded folders, open editors, watch list, and outline-panel options. This file is stripped when the IDE generates a .twinpack for distribution.

Settings file

Always present (category = 0x04). Contains JSON with project configuration including the build type, references, version numbers, and other project settings.

Typical tree structures

.twinproj (Standard EXE project)

ROOT "NewProject"               (version=1, category=0x00)
  DIR  "Miscellaneous"          (kind=2, category=0x06)
  DIR  "Packages"               (kind=2, category=0x07)
  DIR  "ImportedTypeLibraries"  (kind=2, category=0x05)
  DIR  "Resources"              (kind=2, category=0x02)
    DIR  "ICON"                 (kind=2, category=0x00)
      FILE "twinBASIC.ico"      (kind=1, category=0x00)
  DIR  "Sources"                (kind=2, category=0x03)
    FILE "Form1.tbform"         (kind=1, category=0x00)
    FILE "Form1.twin"           (kind=1, category=0x00)
  FILE "Settings"               (kind=1, category=0x04)
  FILE ".meta"                  (kind=1, category=0x00)

.twinpack (distributed package)

ROOT "CustomControlsPackage"    (version=1, category=0x00)
  FILE "CHANGELOG.md"           (kind=1, category=0x00)
  FILE "LICENCE.md"             (kind=1, category=0x00)
  DIR  "Miscellaneous"          (kind=2, category=0x06)
    FILE "frmTextbox.png"       (kind=1, category=0x00)
  DIR  "ImportedTypeLibraries"  (kind=2, category=0x05)
  FILE "Settings"               (kind=1, category=0x04)
  DIR  "Sources"                (kind=2, category=0x03)
    FILE "WaynesGrid.twin"      (kind=1, category=0x00)
  DIR  "Resources"              (kind=2, category=0x02)
    DIR  "MANIFEST"             (kind=2, category=0x00)
      FILE "#1.xml"             (kind=1, category=0x00)
    DIR  "BITMAP"               (kind=2, category=0x00)
      FILE "twinBASIC.bmp"      (kind=1, category=0x00)
  DIR  "Packages"               (kind=2, category=0x07)

Notes

  • Child entry order within a directory is not sorted; it reflects the insertion order within the IDE.
  • The format has no index or offset table — entries must be read sequentially from the start of the file.
  • The .twinproj format is also used for the file system of the IDE itself; the same binary encoding applies.