MCPcopy Create free account
hub / github.com/alecazam/kram

github.com/alecazam/kram @v1.7.30

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.7.30 ↗ · + Follow
13,754 symbols 28,207 edges 561 files 3,004 documented · 22% updated 7d agov1.7.30 · 2025-03-23★ 1743 open issues

Browse by type

Functions 11,186 Types & classes 2,567 Endpoints 1
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

The suite of kram tools below. I hope these improve your game, app, and art development.

kram-profile

Display profile traces (f.e. Perfetto) quickly in an application for optimizing memory, builds, and cpu/gpu timings https://github.com/alecazam/kram/tree/main/kram-profile

hslparser

Parses HLSL syntax and generates readable HLSL/MSL code without transpiling. DXC is then used to compile to spirv. https://github.com/alecazam/kram/tree/main/hlslparser

vectormath

Fast vector math based around clang vector extensions. Requires clang but accelerated for arm64/neon, x64/avx2+fma+f16c. https://github.com/alecazam/kram/tree/main/libkram/vectormath

libkram.a, libkram-ios.a, kram.lib

C++11 library from 200 to 800KB in size depending on encoder options. Compiles for iOS/macOS (arm64), win/linux (x64).

kram, kram.exe

C++11 main to libkram to create CLI tool. Encode/decode/info on PNG/KTX/KTX2/DDS files with LDR/HDR and BC/ASTC/ETC2. Runs on macOS(arm64), win/linux(x64).

kram-thumb-win.dll

Windows thumbnailer for DDS/KTX/KTX2. Go to build or bin folder. Install with "regsvr32.exe kram-thumb-win.dll". Uninstall with "regsvr32.exe /u kram-thumb-win.dll"

https://github.com/alecazam/kram/tree/main/kram-thumb-win

kramv.app

ObjC++ viewer for PNG/KTX/KTX2/DDS supported files from kram. Uses Metal compute and shaders, eyedropper, grids, debugging, preview. Supports HDR and all texture types. Mip, face, volume, and array access. No dmg yet, just drop onto /Applications folder. Runs on macOS (arm64). Generates Finder thumbnails and QuickLook previews via modern macOS app extension mechanisms.

Diagrams and screenshots can be located here: https://www.figma.com/design/bPmPSpBGTi2xTVnBDqVEq0/kram?node-id=0-1&t=OnP0wHcDOmg7b7Vg-1

Releases includes builds for macOS (Xcode 15.3 - arm64/x64/clang) and Windows x64 (VS 2022 - x64/clang) and Linux (ubuntu-x64/clang). kramv for macOS, kram for macOS/Win/Linux, libkram for macOS/iOS/Win/Linux, win-thumb-kram for Win. Android library via NDK is possible, but f16 support is spotty on devices.

About kram

kram is a wrapper to several popular encoders. Most encoders have sources, and have been optimized to use very little memory and generate high quality encodings at all settings. All kram encoders are currently CPU-based. Some of these encoders use SSE, and a SSE to Neon layer translates those. kram was built to be small and used as a library or app. It's also designed for mobile and desktop use. The final size with all encoders is under 1MB, and disabling each encoder chops off around 200KB down to a final 200KB app size via dead-code stripping. The code should compile with C++11 or higher.

kram focuses on sending data efficiently and precisely to the encoders. kram handles srgb and premul at key points in mip generation. Source files use mmap to reduce memory, but fallback to file ops if that fails. Temp files are generated for output, and then renamed in case the app fails or is terminated. Mips are done in-place, and mip data is written out to a file to reduce memory usage. kram leaves out BC2 and etcrgb8a1 and PVRTC. Also BC6 still needs an encoder, and ASTC HDR encoding needs a bit more work to pull from half4/float4 source pixels.

Many of the encoder sources can multithread a single image, but that is unused. kram is designed to batch process one texture per core/thread via a python script or a C++11 task system inside kram. This can use more ram depending on the core count. Texture-per-process and scripted modes currently both take the same amount of CPU time, but scripted mode is best if kram ever adds GPU-accelerated encoding.

Similar to a makefile system, the script sample kramtexture.py uses modstamps to skip textures that have already been processed. If the source png/ktx/ktx2 is older than the output, then the file is skipped. Command line options are not yet compared, so if those change then use --force on the python script to rebuild all textures. Also a crc/hash could be used instead when modstamp isn't sufficient or the same data could come from different folders.

About kramv

kramv is a viewer for the BC/ASTC/ETC2 LDR/HDR KTX/KTX2/DDS textures generated by kram from LDR PNG and LDR/HDR KTX/KTX2/DDS sources. kramv decodes ASTC/ETC2 textures on macOS Intel, where the GPU doesn't support them. macOS with Apple Silicon supports all three formats, and doesn't need to decode. I have macOS Intel support disabled as of 1/25, but can be re--enabled in the xcode project.

kramv uses ObjC++ with the intent to port to Windows C++ as time permits. Uses menus, buttons, and keyboard handling useful for texture triage and analysis. Drag and drop folders, bundles, and click-to-launch are supported. Recently used textures/folders/bundles are listed in the menu. The app currently shows a single document at a time. Subsequent opens reuse the same document Window. With bundles and folders, kramv will attempt to pair albedo and normal maps together by filename for the preview.

Preview mode provides lighting, sdf cutoff, and mip visuals for a given texture. Multiple shapes can help identify inconsistent normal maps. The u-axis advances counterclockwise, and v-axis advances down on the shapes. +Y OpenGL normals are assumed, not -Y DirectX convention. Lighting appears up and to the right when normal maps are correctly specified.

In non-preview mode, point sampling in a pixel shader is used to show exact pixel values of a single mip, array, and face. Debug modes provide pixel analysis. KramLoader shows synchronous cpu upload to a private Metal texture, but does not yet supply the underlying KTXImage. Pinch-zoom and pan tries to keep the image from onscreen, and zoom is to the cursor so navigating feels intuitive.

Compute shaders are used to sample a single pixel sample from the gpu texture for the eyedropper. This simplifies adding more viewable formats in the future, but there is not a cpu fallback. Normal.z is reconstructed and displayed in the hud, and linear and srgb channels are shown.

Formats - R/RG/RGBA 8/16F/32F, BC/ETC2/ASTC,  RGB has limited import support
Container Types - KTX, KTX2, PNG
Content Types - Albedo, Normal, SDF, Height
Debug modes - transparent, color, non-zero, gray, +x, +y, xy >= 1
Texture Types - 1darray (no mips), 2d, 2darray, 3d (no mips), cube, cube array

⇧ decrement any advance/toggle listed below

? - show keyboard shortcuts
P - toggle preview, disables debug mode, shows lit normals, and mips and filtering are enabled
G - advance grid, none, pixel grid, block grid, atlas grid (32, 64, 128, 256),
D - advance debug mode
H - toggle hud
U - toggle ui
V - toggle vertical vs. horizontal buttons
I - show texture info in overlay
W - toggle wrap/address filter, scales uv from [0,1] to [0,2] and changes sampler to wrap/repeat
A - show all - arrays, faces, slices and mips all on-screen

1/2/3/4 - show rgba channels in isolation, alpha as grayscale
7 - toggle signed/unsigned
8 - toggle shader premul, shader does this post-sample so only correct for point-sampling not preview

R - reload from disk if changed, zoom to fit (at 1x with ⇧)
0 - fit the current mip image to 1x, or fit view.  (at 1x with ⇧).

Y - advance array 
F - advance face/slide
M - advance mip

S - advance shape mesh (plane, unit box, sphere, capsule), displays list, esc to get out of list
C - advance shape channel (depth, uv, face normal, vtx normal, tangent, bitangent, mip)
L - advance lighting mode (none, diffuse, diffuse + specular)
T - toggle tangent generation

↓ - advance bundle/folder image (can traverse zip of ktx/ktx2 files), displays list, esc to get out of list
→ - advance counterpart (can see png, then encodes if viewing folders).  Not yet finished.

Limitations

Texture processing is complex and there be dragons. Just be aware of some of the limitations of kram and encoding. Lossy compression can only solve so much. ASTC and BC4-7 are newer formats, but all formats have time and quality tradeoffs. And encoder quality and issues remain. WebGL is still often stuck with older formats due to lack of implemented extensions. And all formats need endpoints/selectors reordering and zstd compression that KTX2 offers. I added a platform called "any" to with KTX2 holding UASTC+zstd and also ETC2/ASTC/BC+zstd. The scripts bundle up textures in an archive, but these should go to resource packs and asset catalogs which get signed and can have ODR applied.

GPU - none of the encoders use the GPU, so cpu threading and multi-process is used

Rescale Filtering - 1x1 point filter
Mip filtering - 2x2 box filter that's reasonable for pow2, and a non-linear filters for non-pow2 so there is no pixel shift 
  done in linear space using half4 storage, in-place to save mem

1D array - no mip support due to hardware, no encoding
3D textures - no mip support, uses ASTC 2d slice encode used by Metal/Android, not exotic ASTC 3d format

BC/ETC2/ASTC - supposedly WebGL requires pow2, and some implementation need top multiple of 4 for BC/ETC2

These formats are disabled:
BC1 w/alpha - may re-enable 3 color for black + rgb
BC2 - not useful
ETC2_RGB8A1 - broken in ETC2 optimizations

BC1 - artifacts from limits of format, artifacts from encoder, use BC7 w/2x memory

ASTC LDR - rrr1, rrrg/gggr, rgb1, rgba must be followed to avoid endpoint storage, requires swizzles
ASTC HDR - encoder uses 8-bit source image, need 16f/32f passed to encoder, no hw L+A mode

R/RG/RGBA 8/16F/32F - use kram or ktx2ktx2+ktx2sc to generate supercompressed ktx2
R8/RG8/R16F - input/output rowBytes not aligned to 4 bytes to match KTX spec, code changes needed

PVRTC - unsupported, no open-source encoders, requires pow2 size

Containers
PVR/Basis/Crunch - unsupoorted 

KTX - only uncompressed, mip levels are unaligned to block size from 4 byte length at chunk 0 
  metadata/props aren't standardized or prevalent
  libkram supports only text props for display in kramv

KTX2 - works in kram and viewer, has aligned levels of mips when uncompressed, 
  libkram supports None/Zlib/Zstd supercompression for read/write
  libkram does not support UASTC/BasisLZ yet

DDS - works in kram and viewer, no mip compression, only BC and explicit formats, extended for ASTC/ETC
  kram/kramv only support newer DX10 style DDS format.  Can view in Preview on macOS too.
  DDSHelper provides load/save.  Pixel data ordered by chunk instead of by mips.  No metadata.

An example pipeline

At build:

* Lossless 8u/16F/32F KTX2 sources 2D, 2D, cube, and 2D atlas textures with zstd mips.  Editing these in Photoshop/Gimp is still an issue.
* Need to stop basing pipelines around PNG.  This is a limited source format, but supported by editors.
* Textures should be higher resolution, and checked into source control (git-lfs or p4).  
* Some sort of scripting to supply encoder preset index for textures. 

* Drop mips and encode to KTX using kram using the encoder preset
* Build 2D array or 2D atalas assets and name/uv locations for those assets.
* Convert KTX to KTX2 via ktx2ktx2 + ktx2sc as lossy encoded ETC2/BC/ASTC+zstd or UASTC+rdo+zstd
* Bundle into an Asset Catalog (macOS/iOS), or resource pack (Android) for slicing and on-demand resource loading

At runtime:

* Mmap load all KTX2 textures read-only into memory using KramLoader.  This is the backing-store.
* Decode smaller faces/slices/array and their mips and upload to staging buffer and then gpu transfer/twiddle to private texture. 
* For example, can upload all lower mips in 1/3rd the space and skip all the top mips.  Textures without mips cannot do this.

* Use sparse texturing hardware or readback to indicate what mips are accessed by the hardware.
* Purge top mips of large unused textures, but keep the bottom mips.
* Upload top mips as needed and memory allows.

Building

kram uses an explicit Xcode workspace and projects on Apple platforms. CMake can't clean, build workspaces, or handle app extensions needed for thumbnails/previews. I spent a lot of time trying to keep CMake working since it keeps kram from being tied to Xcode releases, but I also wanted to add better Finder integration. These all live in 'build2' to distinguish from the 'build' directory created for CMake. Like CMake, the cibuild.h script runs xcodebuild from the command line to generate all the libraries and apps into the bin directory. Note that Xcode has never been able to simultaneously open the same project included in different workspaces, so organize derivative workspaces carefully.

./scripts/cibuild.h

open build2/kram.xcworkspace

kram was using CMake to setup the projects and build, but it doesn't support workspaces, clean, or the thumbnail/preview extension linking. As a result, kramv.app, kram, and libkram are generated. So I'm building kramv.app and everything with a custom Xcode project now. The library can be useful in apps that want to include the decoder, or runtime compression of gpu-generated data.

For Mac, the CMake build is out-of-source, and can be built from the command line, or debugged from the xcodeproj that is built. Ninja and Makefiles can also be generated from cmake, but remember to trash the CMakeCache.txt file.

mkdir build
cmake .. -G Xcode

cmake --build . --config Release
or
open kramWorkspace.xcodeproj
or
cmake --install ../bin --config Release

For Windows, CMake is still used. CMake build libkram, kramc, and kram-thumb-win.dll. This uses the clang compiler and x64 only.

mkdir build
cmake .. -G "Visual Studio 16 2019" -T ClangCL -A x64
or
cmake .. -G "Visual Studio 17 2022" -T ClangCL -A x64

cmake --build . --config Release
or
open kramWorkspace.sln
or
# not sure if install works on Win
cmake --install ../bin --config Release

There are various CMake settings that control the various encoders. Each of these adds around 200KB. I tested with each of these turned off,

Core symbols most depended-on inside this repo

Shape

Method 6,105
Function 5,081
Class 2,406
Enum 161
Route 1

Languages

C++100%
Python1%

Modules by API surface

libkram/simdjson/simdjson.h712 symbols
kram-profile/CBA/simdjson.h712 symbols
libkram/vectormath/sse2neon.h477 symbols
libkram/vectormath/sse2neon-arm64.h477 symbols
libkram/zstd/zstddeclib.cpp371 symbols
libkram/fmt/core.h300 symbols
libkram/transcoder/basisu_transcoder.cpp293 symbols
libkram/fmt/format.h288 symbols
libkram/fmt/chrono.h285 symbols
libkram/lodepng/lodepng.cpp246 symbols
libkram/eastl/include/EASTL/numeric_limits.h216 symbols
libkram/simdjson/simdjson.cpp202 symbols

For agents

$ claude mcp add kram \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page