# NYX Graphics — icosahedra.com > Normal maps, BCn/DDS texture compression, signed distance fields and > SDF/MSDF font atlases. Everything runs locally — the pages in a tab, the same > tools in a headless browser or a shell. Nothing is uploaded. ## Agents: do not automate the tool pages /normals/, /dxt/, /sdf/ and /font/ only give results back as browser downloads. Use one of the two routes below; both run the pages' own modules and the same wasm, so the bytes are identical to what the download buttons produce. **A browser, nothing installed.** loads the CLI as `window.nyx`: ```js await page.goto('https://icosahedra.com/cli/'); const out = await page.evaluate(`nyx.sdf('${pngBase64}', { chan: 3, size: 256 })`); ``` From your own page or worker, any origin: `const { sdf, run } = await import('https://icosahedra.com/api/nyx.js')` **A shell**, with JavaScriptCore (ships with macOS) or Node 22.7+: ```sh curl -fsSL https://icosahedra.com/cli/install.sh -o install.sh sh install.sh ./nyx # 37 files, ~1 MB, no build step ./nyx/nyx.sh sdf logo.png --chan 3 --size 256 ``` ## API ``` nyx.(input, options) -> { ok, file, files, json, stdout, stderr, exitCode } input base64 | data: URL | Uint8Array | ArrayBuffer { 'logo.png': bytes } when the name matters — nyx dxt names its DDS after it nyx.dxt takes source slots: { a: bytes, b: bytes, c: bytes, d: bytes } options one key per flag listed below, without the dashes and camelCased: --atlas-max 4096 -> atlasMax: 4096 · --psnr -> psnr: true · --no-simd -> simd: false an array is whatever the flag takes: eq: [3,2.5,2,1.5,1] is one value, map: ['R=A.LUMA', 'A=ONE'] is --map twice file the output as base64, when the run wrote exactly one file; else null files { name: base64 }, always · pass binary: true for Uint8Array values json stdout parsed, when the run printed JSON (--json; --json-summary for font) exitCode 0 ok · 1 usage error · 2 runtime failure · ok === (exitCode === 0) stderr progress and errors, as the shell would have printed them nyx.spec('sdf') every option of one tool, with its default, range and help, keyed the way you would write it — ask rather than guess nyx.run('sdf in.png --chan 3', { 'in.png': bytes }) any flag, same result object nyx.preload() fetch the ~900 KB of wasm early An option a tool does not have comes back as exitCode 1 and a stderr naming every option it does have, so a wrong guess costs one call, not a lookup. shell: nyx [options] — same flags, same defaults, same exit codes, --help per tool, files written to disk instead of returned ``` Input is PNG, any bit depth or colour type, non-interlaced; fonts are TTF, OTF or TTC. There is no JPEG or WebP decoder off the browser. In a page the work runs on the calling thread, so use a worker if the caller has a UI to keep alive. Defaults below are the web page's controls, so a default run reproduces the page. ## nyx normals · nyx.normals(input, options) Normal, height and cavity-AO maps from a height or depth image. ``` nyx normals [options] depth.png height or depth image; a 16-bit PNG keeps full precision, anything else is 8-bit luminance --out-dir . where the default names land --normal — write the 8-bit normal map here --normal16 — write the 16-bit normal map here (recomputed from the float normals, like the page) --height — write the 8-bit processed height view here --height16 — write the input depth as a 16-bit grey PNG (needs 16-bit input) --ao — write the cavity AO map here --all off write normal, height and AO (and the 16-bit height when the input has it) under the page's names --black 0 black point, % (0..99) --white 100 white point, % (1..100) --gamma 1 height gamma (0.25..4) --sharpen 0 unsharp amount (0..2) --smooth 1 gaussian smoothing sigma, px (0..8) --[no-]invert off dark pixels become high --power 1 overall height, as the page's ×gain (0..100) --eq 2,2,2,2,2 five band gains, finest to low (×2 is the page's reference) (0..100) --convention gl OpenGL +Y or DirectX −Y (gl|dx) --[no-]dither on 4×4 Bayer dither on the normal map --ao-intensity 1 cavity AO strength (0..4) --[no-]simd on use heightfield-simd.wasm where the engine runs it --json off print the summary as JSON on stdout --quiet off no progress on stderr ``` ## nyx dxt · nyx.dxt(input, options) Pack up to four sources into RGBA, compress to BC1/3/4/5/7 and write a DDS. ``` nyx dxt -a [-b/-c/-d ...] [options] -a — source slot A -b — source slot B -c — source slot C -d — source slot D --preset custom channel layout, format and colour space in one (custom|ue-orm|unity-mask|bc5-normal|passthrough) --map — one output channel, e.g. R=A.LUMA or G=B.R,invert,black=12,white=240,gamma=1.7 or A=ONE. Repeatable; overrides the preset --format bc7 block format (bc1|bc3|bc4|bc5|bc7) --quality high encoder tier (fast|high) --[no-]srgb off tag the DXGI format sRGB and filter mips in linear light (BC1, BC3 and BC7 only) --[no-]mips on write the whole mip chain --width — output width; the first slot in use sets it by default (1..16384) --height — output height (1..16384) --dds — output DDS (default -.dds in --out-dir) --png — also write the packed RGBA as a PNG --out-dir . where the default names land --psnr off decode the base level back and report PSNR over the channels the format stores --list-presets off print the preset table and exit --[no-]simd on use bcn-simd.wasm where the engine runs it --json off print the summary as JSON on stdout --quiet off no progress on stderr ``` ## nyx sdf · nyx.sdf(input, options) Signed distance field from a shape image: 1-channel SDF, 2-channel convex-corner field or 3-channel MSDF. ``` nyx sdf [options] input.png the shape: alpha when it has any, otherwise luminance --out — output PNG (default sdf-ch-x.png in --out-dir) --out-dir . where the default name lands --chan 1 1 standard, 2 convex corners (Green 2007), 3 MSDF (1..3) --size 64 output size on the long edge, in texels (8..4096) --spread 16 distance range in output pixels (1..256) --pad 0 padding in output pixels; negative crops in --threshold 128 alpha or luminance cutoff (1..254) --sign inside which side is positive (inside|outside) --json off print the summary as JSON on stdout --quiet off no progress on stderr ``` ## nyx font · nyx.font(input, options) SDF, MSDF or MTSDF glyph atlas with metrics and kerning, straight from a TTF, OTF or TTC. ``` nyx font [options] font.ttf TrueType, OpenType or a TrueType collection (WOFF is not supported) --out-dir . where the default names land --png — atlas PNG (default --px.png) --json — layout JSON (default --px.json) --font — venus .font bytes (SDF mode only) --all off also write the .font when the mode is sdf --mode msdf 1, 3 or 4 channels (sdf|msdf|mtsdf) --em 48 glyph size, pixels per em (4..512) --px-range 8 distance range in texels (the shader's pxRange) (1..64) --padding 1 texels between glyph boxes (0..16) --atlas-max 2048 largest atlas edge (64..16384) --[no-]pot off power-of-two atlas height (otherwise a multiple of 32) --outline curves evaluate the outline exactly, or rasterize it first (curves|raster) --raster-factor 8 raster upscale, and the curve path's fallback (4|8|12|16) --y-origin bottom atlas bounds origin (bottom|top) --charset latin comma-separated presets; ASCII is always included --chars extra characters, literally --ranges extra code points, e.g. "U+2190-21FF,20AC" --face 0 face index in a collection (0..255) --info off print the face, its metrics and the charset coverage, and stop --list-charsets off print the charset presets and exit --json-summary off print the run summary as JSON on stdout --quiet off no progress on stderr ``` ## Pages - — normal, height and cavity-AO maps, five-band EQ, 16-bit, optional on-device AI depth (browser only) - — channel packing, BC1/3/4/5/7, DDS with mips, decode and PSNR - — 1-, 2- or 3-channel distance fields - — SDF/MSDF/MTSDF atlases, msdf-atlas-gen JSON, venus .font - — the above for people, and the page that carries `window.nyx` - — layout, the three places CLI output differs from the page, how it is tested - — third-party notices and licenses ## Notes - Nothing is uploaded by any route: every request is for this site's own files. - The compression, distance-field and font code is compiled Rust (the venus engine) shipped as WebAssembly, used unchanged by the pages, the browser route and the CLI.