HyperbasisHyperbasisDocs
Home

Compression

How Hyperbasis compresses ARWorldMap data.

Overview

ARWorldMap data is typically 5-50 MB. Hyperbasis uses zlib compression to reduce storage size and upload times.

Compression API

public enum HBCompression {
    public static func compress(_ data: Data, level: HBCompressionLevel) throws -> Data
    public static func decompress(_ data: Data) throws -> Data
}

Compression Levels

public enum HBCompressionLevel {
    case none      // No compression
    case balanced  // zlib default (~40% reduction)
}

None

  • No compression applied
  • Fastest save/load times
  • Largest file sizes
  • Best for development/debugging

Balanced

  • zlib default compression
  • ~40% size reduction on typical ARWorldMap data
  • Slight CPU overhead
  • Recommended for production

Implementation Details

Hyperbasis uses Apple's Compression framework with the zlib algorithm:

import Compression

// Compression
let compressedSize = compression_encode_buffer(
    destinationBuffer,
    destinationCapacity,
    sourceBuffer,
    sourceSize,
    nil,
    COMPRESSION_ZLIB
)

// Decompression
let decompressedSize = compression_decode_buffer(
    destinationBuffer,
    destinationCapacity,
    sourceBuffer,
    sourceSize,
    nil,
    COMPRESSION_ZLIB
)

Size Comparisons

EnvironmentUncompressedCompressedReduction
Small room8 MB4.8 MB40%
Medium room18 MB10.8 MB40%
Large space45 MB27 MB40%
Note

ARWorldMap data compresses well because it contains redundant feature point data. Compression ratios are consistent across different environment sizes.

Configuration

Set compression level in HBStorageConfig:

// No compression (development)
let devConfig = HBStorageConfig(
    backend: .localOnly,
    syncStrategy: .manual,
    compression: .none
)

// Balanced compression (production)
let prodConfig = HBStorageConfig(
    backend: .supabase(url: url, anonKey: key),
    syncStrategy: .onSave,
    compression: .balanced
)

When to Use Each Level

Use .none when:

  • Debugging world map issues
  • CPU is constrained
  • Storage space is unlimited
  • Development/testing

Use .balanced when:

  • Production deployment
  • Cloud sync is enabled
  • Storage costs matter
  • Normal usage

Error Handling

public enum HBStorageError: LocalizedError {
    case compressionFailed(underlying: Error)
    case decompressionFailed(underlying: Error)
}
do {
    let space = try await storage.loadSpace(id: spaceId)
} catch HBStorageError.decompressionFailed(let error) {
    // Handle corrupted or incompatible compression
    print("Failed to decompress world map: \(error)")
}

Compression Flag

Stored data includes a flag indicating whether compression was used:

{
  "id": "space-uuid",
  "worldMapData": "base64-data...",
  "isCompressed": true
}

This ensures data compressed with one setting can be read regardless of current configuration.

Performance Considerations

Compression Time

SizeCompression Time
10 MB~50ms
25 MB~120ms
50 MB~250ms

Decompression Time

Decompression is typically 2-3x faster than compression.

Memory Usage

Compression requires temporary buffers. For a 50 MB world map:

  • ~50 MB source buffer
  • ~50 MB destination buffer (pre-allocated)
  • Total: ~100 MB peak memory during compression
Warning

On memory-constrained devices, consider saving spaces when the app has available memory, not during memory pressure situations.

Next Steps