HomeJournalThis post

DCT Glitch Art by Coefficient Editing

Create deterministic DCT glitch art with an 8×8 transform, named coefficient gestures, error maps, pixel hashes, and validated PNG export.

JP
JP Casabianca
AI Engineer and Product Designer · full-stack delivery · Bogotá

DCT glitch art can be designed by editing decoded 8×8 cosine coefficients and exporting a new valid image. This tutorial keeps transform math, channel policy, energy, clipping, hashes, and the JPEG boundary inspectable.

DCT glitch art begins after decoding

This studio does not corrupt JPEG bytes. It decodes or generates pixels, groups them into 8×8 blocks, transforms values into cosine coefficients, edits those coefficients, reconstructs pixels, and exports a new valid PNG. This discrete cosine transform art boundary makes DCT glitch art reproducible without pretending to manipulate an entropy-coded JPEG stream.

The distinction matters creatively. Byte corruption depends on container markers, entropy coding, decoder recovery, and undefined damage. Coefficient editing works in a named frequency basis with explicit masks and finite values. The result can still feel broken, but the process is inspectable and repeatable.

The ITU-T T.81 record is the standards anchor for JPEG terminology and its 8×8 transform context. This generated fixture is not a JPEG encoder and makes no bitstream-parity claim. It uses a generated image, centered sample values, an orthonormal DCT, clamping on reconstruction, and Canvas PNG serialization. Those choices form the recipe’s pixel contract.

Define the generated pixel contract

Start with a known source. The studio generates a test card from geometric fields, stripes, a radial highlight, and seeded grain. Its dimensions are multiples of eight, avoiding hidden padding in the supported path. Odd dimensions are rejected because this artifact does not implement a padding policy. The receipt stores source size, generator version, seed, channel mode, and pixel hash.

DCT glitch art can operate on luminance alone or on RGB channels independently. This studio implements independent RGB-channel editing so colored ringing and clip counts remain observable. A luminance-only design would require a declared conversion and recombination policy and is outside this artifact's supported path. The recipe names the implemented channel policy so it cannot be mistaken for JPEG’s complete color pipeline.

Canvas pixel access follows the WHATWG pixel-manipulation model. Browser color management may affect imported imagery, which is why the included generator is the deterministic comparison path. If you add a photograph, record its license, decode environment, orientation, and color-space handling before comparing hashes.

Read an 8×8 block as frequencies

The two-dimensional DCT expresses an 8×8 block as 64 cosine basis weights. The coefficient at (0,0) is DC, representing the block’s average under the chosen normalization. Moving right increases horizontal frequency; moving down increases vertical frequency. The far corner oscillates rapidly in both directions.

The 64-tile basis atlas is not decoration. Each tile shows the spatial pattern created by one unit coefficient, with row and column labels plus neighborhoods for DC, directional, diagonal, and high-frequency behavior. A semantic grid lists the same locations so the idea survives without the SVG.

For DCT glitch art, think of a coefficient edit as choosing which block-scale rhythms survive. Removing low AC values flattens gradients while retaining edges. Amplifying a diagonal band creates woven interference. Swapping bands relocates structure. An 8x8 block glitch is therefore a local basis edit, not evidence that encoded bytes were damaged. Unlike Fourier phase language, the real-valued DCT basis and block boundaries should be described directly; “phase-like rhythm” is an artistic analogy, not a transform variable exposed here.

The 64-tile cosine basis atlasEvery tile renders the exact 8×8 spatial field produced by one unit coefficient under the studio’s orthonormal inverse DCT normalization.
The 64-tile cosine basis atlas
Every tile renders the exact 8×8 spatial field produced by one unit coefficient under the studio’s orthonormal inverse DCT normalization.
All 64 orthonormal unit-coefficient basis fields
CoordinateSignHorizontal frequencyVertical frequency
(0,0)positive constantu=0 cosine indexv=0 cosine index
(1,0)alternating positive and negative lobesu=1 cosine indexv=0 cosine index
(2,0)alternating positive and negative lobesu=2 cosine indexv=0 cosine index
(3,0)alternating positive and negative lobesu=3 cosine indexv=0 cosine index
(4,0)alternating positive and negative lobesu=4 cosine indexv=0 cosine index
(5,0)alternating positive and negative lobesu=5 cosine indexv=0 cosine index
(6,0)alternating positive and negative lobesu=6 cosine indexv=0 cosine index
(7,0)alternating positive and negative lobesu=7 cosine indexv=0 cosine index
(0,1)alternating positive and negative lobesu=0 cosine indexv=1 cosine index
(1,1)alternating positive and negative lobesu=1 cosine indexv=1 cosine index
(2,1)alternating positive and negative lobesu=2 cosine indexv=1 cosine index
(3,1)alternating positive and negative lobesu=3 cosine indexv=1 cosine index
(4,1)alternating positive and negative lobesu=4 cosine indexv=1 cosine index
(5,1)alternating positive and negative lobesu=5 cosine indexv=1 cosine index
(6,1)alternating positive and negative lobesu=6 cosine indexv=1 cosine index
(7,1)alternating positive and negative lobesu=7 cosine indexv=1 cosine index
(0,2)alternating positive and negative lobesu=0 cosine indexv=2 cosine index
(1,2)alternating positive and negative lobesu=1 cosine indexv=2 cosine index
(2,2)alternating positive and negative lobesu=2 cosine indexv=2 cosine index
(3,2)alternating positive and negative lobesu=3 cosine indexv=2 cosine index
(4,2)alternating positive and negative lobesu=4 cosine indexv=2 cosine index
(5,2)alternating positive and negative lobesu=5 cosine indexv=2 cosine index
(6,2)alternating positive and negative lobesu=6 cosine indexv=2 cosine index
(7,2)alternating positive and negative lobesu=7 cosine indexv=2 cosine index
(0,3)alternating positive and negative lobesu=0 cosine indexv=3 cosine index
(1,3)alternating positive and negative lobesu=1 cosine indexv=3 cosine index
(2,3)alternating positive and negative lobesu=2 cosine indexv=3 cosine index
(3,3)alternating positive and negative lobesu=3 cosine indexv=3 cosine index
(4,3)alternating positive and negative lobesu=4 cosine indexv=3 cosine index
(5,3)alternating positive and negative lobesu=5 cosine indexv=3 cosine index
(6,3)alternating positive and negative lobesu=6 cosine indexv=3 cosine index
(7,3)alternating positive and negative lobesu=7 cosine indexv=3 cosine index
(0,4)alternating positive and negative lobesu=0 cosine indexv=4 cosine index
(1,4)alternating positive and negative lobesu=1 cosine indexv=4 cosine index
(2,4)alternating positive and negative lobesu=2 cosine indexv=4 cosine index
(3,4)alternating positive and negative lobesu=3 cosine indexv=4 cosine index
(4,4)alternating positive and negative lobesu=4 cosine indexv=4 cosine index
(5,4)alternating positive and negative lobesu=5 cosine indexv=4 cosine index
(6,4)alternating positive and negative lobesu=6 cosine indexv=4 cosine index
(7,4)alternating positive and negative lobesu=7 cosine indexv=4 cosine index
(0,5)alternating positive and negative lobesu=0 cosine indexv=5 cosine index
(1,5)alternating positive and negative lobesu=1 cosine indexv=5 cosine index
(2,5)alternating positive and negative lobesu=2 cosine indexv=5 cosine index
(3,5)alternating positive and negative lobesu=3 cosine indexv=5 cosine index
(4,5)alternating positive and negative lobesu=4 cosine indexv=5 cosine index
(5,5)alternating positive and negative lobesu=5 cosine indexv=5 cosine index
(6,5)alternating positive and negative lobesu=6 cosine indexv=5 cosine index
(7,5)alternating positive and negative lobesu=7 cosine indexv=5 cosine index
(0,6)alternating positive and negative lobesu=0 cosine indexv=6 cosine index
(1,6)alternating positive and negative lobesu=1 cosine indexv=6 cosine index
(2,6)alternating positive and negative lobesu=2 cosine indexv=6 cosine index
(3,6)alternating positive and negative lobesu=3 cosine indexv=6 cosine index
(4,6)alternating positive and negative lobesu=4 cosine indexv=6 cosine index
(5,6)alternating positive and negative lobesu=5 cosine indexv=6 cosine index
(6,6)alternating positive and negative lobesu=6 cosine indexv=6 cosine index
(7,6)alternating positive and negative lobesu=7 cosine indexv=6 cosine index
(0,7)alternating positive and negative lobesu=0 cosine indexv=7 cosine index
(1,7)alternating positive and negative lobesu=1 cosine indexv=7 cosine index
(2,7)alternating positive and negative lobesu=2 cosine indexv=7 cosine index
(3,7)alternating positive and negative lobesu=3 cosine indexv=7 cosine index
(4,7)alternating positive and negative lobesu=4 cosine indexv=7 cosine index
(5,7)alternating positive and negative lobesu=5 cosine indexv=7 cosine index
(6,7)alternating positive and negative lobesu=6 cosine indexv=7 cosine index
(7,7)alternating positive and negative lobesu=7 cosine indexv=7 cosine index
Figure 1: These are 64 computed spatial bases—not repeated gradients—with coordinate, sign, and frequency preserved in the semantic table.

Build forward and inverse DCT oracles

Implement the forward transform from the equation before optimizing it. For each output coordinate, sum every centered input sample multiplied by its horizontal and vertical cosine basis, including the normalization factors. The inverse sums coefficients against the same orthonormal basis. With no edits, reconstruction should differ only by floating-point tolerance before rounding.

Two fixtures catch common mistakes. A constant block must place essentially all energy in DC. A single basis tile should concentrate energy at its matching coordinate, with near-zero residue elsewhere. The studio also reports maximum round-trip error for a generated block and rejects non-finite coefficients.

DCT glitch art benefits from slow, readable math during development. A 64×64 nested calculation is acceptable for a small teaching canvas. If you later use a separable or GPU implementation, keep these oracles as a reference. Optimization without a trusted inverse can turn a normalization bug into a style and make every published recipe irreproducible.

Design coefficient edits as named gestures

A gesture is a pure mapping from coefficient position and value to a new value. “Quiet horizon” attenuates vertical frequencies above a threshold. “Diagonal relay” swaps two diagonal bands. “Granite quantize” rounds high-frequency coefficients to coarse steps. “Sign loom” flips alternating mid-band signs. Each gesture stores parameters rather than mutating hidden global state.

The edition atlas shows four recipes with their masks, results, error maps, hashes, and rejection notes. This is JPEG coefficient editing only in the broad decoded-coefficient sense; the artifact never patches a JPEG bitstream. DCT glitch art becomes more coherent when gestures have visual intent and names. Random coefficient damage can be lively, but a seed and selection policy are still required if it will be reproduced.

Limit magnitude after edits and count every clamp. A mask may select zero coefficients on a flat block; that is a valid no-op to report. Avoid division by a data-dependent value without a zero policy. The studio rejects non-finite output before inverse transformation, because exporting a picture should never hide an invalid numerical state.

Keep luminance and color decisions explicit

Editing each RGB channel separately can produce colored ringing and seams. Editing only a luminance-like channel preserves more hue relationships but depends on the chosen conversion and recombination. Neither is inherently correct for art. The recipe should name channel ownership so viewers can understand why an edge became chromatic or remained neutral.

The studio's independent RGB path transforms and reconstructs each channel with the same orthonormal basis. Values are clamped to the byte range, and the receipt counts low and high clips by channel. DCT glitch art often uses clipping as part of the look; counting it does not forbid it. It separates deliberate saturation from an unnoticed overflow. A future luminance path must identify its conversion coefficients and preserve its own oracle fixtures.

If a wide-gamut image is imported, Canvas configuration and serialization require another explicit color contract. This article stays with the generated sRGB-oriented teaching path. Creative freedom grows when the pipeline is named: you can change one channel policy and know which visual consequence belongs to that change.

Expose coefficient energy and pixel damage

Coefficient energy is the sum of squared coefficients under the orthonormal transform. Report it by low, middle, and high bands before and after the gesture. That shows where the recipe moved or removed structure. It does not measure artistic quality. Pixel error maps show the spatial consequence, while clip counts show where reconstruction exceeded the export range.

DCT glitch art can exploit the mismatch between block-local edits and continuous images. Strong changes reveal 8×8 boundaries; gentler masks create texture without an obvious grid. The block–spectrum–reconstruction figure connects one edited coefficient band to visible pixels so the style is not reduced to a control panel.

Compare frequency edits with spatial dithering and multiscale pyramid bands. These methods organize information differently: dithering distributes quantization error in space, pyramids separate scales across filtered images, and this studio edits local cosine coordinates. The comparison is conceptual, not a claim that one technique supersedes another.

Computed block, spectrum, reconstructionA generated source, the exact selected-block coefficient spectrum, the quiet-horizon output, and its absolute error raster come from the same pinned studio transform.generated sourceselected spectrumreconstructionabsolute error ×4recipe: quiet-horizon · strength 1 · independent RGBsource hash: ffe48973output hash: 79966200normalization: orthonormal DCT-II 8×8selected block: x48 y32 · red channeledge policy: 128×96 divisible by eight
Computed block, spectrum, reconstruction
A generated source, the exact selected-block coefficient spectrum, the quiet-horizon output, and its absolute error raster come from the same pinned studio transform.
  1. Generated source hash: ffe48973.
  2. Selected block: x=48, y=32, red channel; its 64 signed coefficients are -143.750, 50.450, 41.310, 10.867, 7.250, -6.488, -0.875, 4.868, 67.992, 80.691, 50.636, 13.429, -5.165, -7.134, 5.957, 9.034, 45.022, 42.309, 19.953, -7.653, -9.110, -14.000, -4.009, 4.052, 6.960, 10.150, -5.090, -11.505, -14.630, -9.843, -2.125, 2.653, -2.030, -2.501, -8.882, -11.594, -7.540, -7.159, 6.975, 6.692, -0.329, -1.455, -3.941, -10.631, -4.177, 5.459, 9.564, 7.547, -0.615, 2.207, 1.300, -0.659, 3.915, 9.668, 8.292, 6.889, 2.160, 2.131, 2.098, 2.971, 1.015, 4.271, 4.797, 4.775.
  3. Recipe: quiet-horizon at strength 1 on independent RGB channels.
  4. Output pixel hash: 79966200.
  5. Absolute-error raster hash: 0ca54b81.
Figure 2: The source, spectrum, edited output, and error view are computed from one deterministic transform path.

Run the frequency-domain studio

Open the browser artifact and choose a named recipe, strength, channel mode, and seed. The generated source, transformed edition, selected block, coefficient heatmap, reconstruction error, and receipt update together. A reset restores the pinned default. Export links remain disabled until the PNG blob successfully decodes in an ImageBitmap.

The DCT glitch art receipt includes generator version, transform normalization, edge policy, channel mode, recipe parameters, source and output pixel hashes, band energies, maximum unedited round-trip error, clip counts, non-finite count, and export validation. These frequency-domain image effects remain tied to a named recipe rather than an unlabeled visual preset. The supported-path hash is deterministic for the pinned browser canvas pipeline; imported images are labeled separately.

Start by selecting no edit and confirm the oracle. Then increase one gesture’s strength. Inspect the selected block before the whole composition. If the edition is interesting only at one accidental setting, save that complete recipe. A reproducible accident is still an artistic decision once its conditions are documented.

Runnable artifact — The studio edits decoded pixel blocks with a teaching DCT and exports a new valid image; it does not patch JPEG entropy-coded bytes or claim JPEG-encoder bitstream parity.

<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>DCT glitch studio</title><style>:root{color-scheme:dark}*{box-sizing:border-box}body{max-width:980px;margin:auto;padding:22px;background:#090b15;color:#f8f7ff;font:16px/1.5 system-ui}button,select,input,a{min-height:44px;padding:8px;font:inherit}.controls{display:flex;gap:10px;flex-wrap:wrap}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}figure{border:1px solid #6772ae;border-radius:14px;padding:12px;margin:0}canvas{width:100%;height:auto;background:#03040a}textarea{width:100%;min-height:240px;background:#03040a;color:#fff}@media(max-width:520px){body{padding:12px}}</style><main><h1>DCT glitch coefficient studio</h1><p>Generated pixels enter an orthonormal 8×8 teaching DCT. This does not patch JPEG entropy-coded bytes.</p><div class="controls"><label>Gesture <select id="gesture"><option>quiet-horizon</option><option>diagonal-relay</option><option>granite-quantize</option><option>sign-loom</option><option>none</option></select></label><label>Strength <input id="strength" type="range" min="0" max="2" value="1" step=".1"></label><label>Channel mode <select id="channel"><option value="independent-rgb">Independent RGB</option><option value="red-only">Red channel only</option></select></label><label>Seed <input id="seed" type="number" value="904"></label><button id="run">Render edition</button><button id="reset" type="button">Reset pinned default</button></div><div class="grid"><figure><canvas id="source" width="128" height="96"></canvas><figcaption>Generated source</figcaption></figure><figure><canvas id="result" width="128" height="96"></canvas><figcaption>Coefficient-edited edition</figcaption></figure><figure><canvas id="spectrum" width="128" height="96"></canvas><figcaption>Selected block spectrum</figcaption></figure><figure><canvas id="error" width="128" height="96"></canvas><figcaption>Absolute reconstruction error</figcaption></figure></div><textarea id="receipt" readonly aria-label="Execution receipt"></textarea><p><a id="png" download="dct-glitch-edition.png">Download valid PNG</a> <a id="json" download="dct-glitch-recipe.json">Download recipe</a></p></main><script>
const N=8,W=128,H=96,id=x=>document.getElementById(x),alpha=k=>k===0?1/Math.sqrt(2):1,clamp=v=>Math.max(0,Math.min(255,Math.round(v)));function rng(seed){let s=seed>>>0;return()=>{s^=s<<13;s^=s>>>17;s^=s<<5;return(s>>>0)/4294967296}}function source(seed){const r=rng(seed),p=[];for(let y=0;y<H;y++)for(let x=0;x<W;x++){const ring=Math.abs(Math.hypot(x-64,y-48)-26)<5?75:0;p.push([clamp(35+x*1.2+ring+r()*12),clamp(35+y*1.7+ring*.45),clamp(105+(x+y)%24*4+r()*8)])}return p}function dct(block){const c=Array(64).fill(0);for(let v=0;v<N;v++)for(let u=0;u<N;u++){let sum=0;for(let y=0;y<N;y++)for(let x=0;x<N;x++)sum+=block[y*N+x]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);c[v*N+u]=.25*alpha(u)*alpha(v)*sum}return c}function idct(c){const b=Array(64).fill(0);for(let y=0;y<N;y++)for(let x=0;x<N;x++){let sum=0;for(let v=0;v<N;v++)for(let u=0;u<N;u++)sum+=alpha(u)*alpha(v)*c[v*N+u]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);b[y*N+x]=.25*sum}return b}function edit(c,name,s){const o=[...c];for(let v=0;v<N;v++)for(let u=0;u<N;u++){const i=v*N+u;if(!u&&!v)continue;if(name==='quiet-horizon'&&v>=3)o[i]*=1-.42*s;if(name==='granite-quantize'&&u+v>=6){const q=6+12*s;o[i]=Math.round(o[i]/q)*q}if(name==='sign-loom'&&u+v>=3&&u+v<=8&&(u+v)%2)o[i]*=-s;if(name==='diagonal-relay'&&u===v&&u>0){const j=v*N+(N-1-u);[o[i],o[j]]=[o[j]*s,o[i]*s]}}return o}function hash(p){let h=2166136261;for(const n of p.flat())h=Math.imul(h^clamp(n),16777619);return(h>>>0).toString(16).padStart(8,'0')}function paint(canvas,p){const ctx=id(canvas).getContext('2d'),im=ctx.createImageData(W,H);p.forEach((v,i)=>im.data.set([...v.map(clamp),255],i*4));ctx.putImageData(im,0,0)}
async function render(){const seed=Number(id('seed').value),gesture=id('gesture').value,strength=Number(id('strength').value),channelMode=id('channel').value,src=source(seed),out=Array(src.length),errors=Array(src.length),energies={before:[0,0,0],after:[0,0,0]};let maxRoundTrip=0,clipLow=0,clipHigh=0,nonFinite=0,selected=[];for(let by=0;by<H;by+=8)for(let bx=0;bx<W;bx+=8)for(let ch=0;ch<3;ch++){const block=[];for(let y=0;y<8;y++)for(let x=0;x<8;x++)block.push(src[(by+y)*W+bx+x][ch]-128);const coeff=dct(block),unedited=idct(coeff);unedited.forEach((v,i)=>maxRoundTrip=Math.max(maxRoundTrip,Math.abs(v-block[i])));const changed=channelMode==='red-only'&&ch!==0?[...coeff]:edit(coeff,gesture,strength),recon=idct(changed);if(bx===48&&by===32&&ch===0)selected=changed;for(let i=0;i<64;i++){const u=i%8,v=Math.floor(i/8),band=u+v<3?0:u+v<8?1:2;energies.before[band]+=coeff[i]**2;energies.after[band]+=changed[i]**2}for(let y=0;y<8;y++)for(let x=0;x<8;x++){const index=(by+y)*W+bx+x,value=recon[y*8+x]+128;if(!Number.isFinite(value))nonFinite++;if(value<0)clipLow++;if(value>255)clipHigh++;(out[index]||(out[index]=[0,0,0]))[ch]=clamp(value)}}for(let i=0;i<src.length;i++){const e=src[i].map((v,ch)=>Math.abs(v-out[i][ch])*4);errors[i]=e.map(clamp)}paint('source',src);paint('result',out);paint('error',errors);const spectrum=Array.from({length:W*H},(_,i)=>{const x=i%W,y=Math.floor(i/W),u=Math.floor(x/(W/8)),v=Math.floor(y/(H/8)),m=Math.log1p(Math.abs(selected[v*8+u]||0))*42;return selected[v*8+u]>=0?[m,80,m*1.7]:[m*1.7,m,80]});paint('spectrum',spectrum);const constant=dct(Array(64).fill(10)),constantAC=constant.slice(1).reduce((s,v)=>s+Math.abs(v),0),basisU=2,basisV=3,basis=Array.from({length:64},(_,i)=>Math.cos((2*(i%8)+1)*basisU*Math.PI/16)*Math.cos((2*Math.floor(i/8)+1)*basisV*Math.PI/16)),basisCoefficients=dct(basis),basisIndex=basisV*8+basisU,basisLeakage=basisCoefficients.reduce((sum,value,index)=>sum+(index===basisIndex?0:Math.abs(value)),0);const data={fixture:'dct-glitch-generated-edition-v2',seed,generator:'geometric-ring-grain-v1',gesture,strength,normalization:'orthonormal DCT-II 8x8',channelMode,channelPolicy:channelMode==='red-only'?'edit red; round-trip green and blue unchanged':'edit each RGB channel independently',sourceDimensions:[W,H],edgePolicy:'dimensions divisible by eight; odd sizes rejected',sourcePixelHash:hash(src),outputPixelHash:hash(out),energyBands:energies,maxUneditedRoundTripError:maxRoundTrip,constantBlockACResidue:constantAC,singleBasisOracle:{coordinate:[basisU,basisV],targetMagnitude:basisCoefficients[basisIndex],leakage:basisLeakage},clipCounts:{low:clipLow,high:clipHigh},nonFinite,jpegBytesPatched:false};const blob=await new Promise(r=>id('result').toBlob(r,'image/png'));let valid=false;try{const bitmap=await createImageBitmap(blob);valid=bitmap.width===W&&bitmap.height===H;bitmap.close()}catch{}data.export={mime:blob.type,bytes:blob.size,valid,dimensions:[W,H],dimensionsMatchSource:valid&&W===data.sourceDimensions[0]&&H===data.sourceDimensions[1]};const receipt=id('receipt');receipt.value=(valid&&nonFinite===0&&maxRoundTrip<1e-9&&constantAC<1e-9&&basisLeakage<1e-9?'PASS: ':'FAIL: ')+JSON.stringify(data,null,2);receipt.dataset.execution=JSON.stringify(data);id('png').href=valid?URL.createObjectURL(blob):'';id('json').href=URL.createObjectURL(new Blob([JSON.stringify(data,null,2)],{type:'application/json'}))}id('run').onclick=render;id('reset').onclick=()=>{id('gesture').value='quiet-horizon';id('strength').value='1';id('channel').value='independent-rgb';id('seed').value='904';render()};render();
</script></html>

Curate a coherent edition

Generate a contact sheet across gestures and strengths, then reject most of it. Keep notes tied to visual intent: “diagonal relay destroys the focal ring,” “granite texture supports the quiet field,” or “color clipping overwhelms the block rhythm.” A rejection ledger prevents the final image from looking like the first preset that executed.

For DCT glitch art, pair every accepted image with its recipe JSON. The image is the artwork; the recipe is its production score. Preserve the generated source hash so future changes to the generator cannot impersonate a transform change. Keep the rejection note beside the accepted edition so selection remains explainable. When adapting the method to photographs, retain license and source metadata beside the recipe.

Contrast the technique with exemplar-based image quilting and directional Kuwahara filtering. Quilting reassembles patches; Kuwahara selects statistics from directional neighborhoods; coefficient gestures reshape local frequencies. Their artifacts may share texture, but their control surfaces and failure modes are distinct.

Four computed recipe editionsEach deterministic recipe card contains its actual coefficient mask, downsampled output, absolute-error view, pixel and error hashes, PNG validation state, and curator note.maskoutputerror ×4 · 0ca54b81pixel 79966200PNG decode: PASSaccepted · restrained fieldquiet-horizonmaskoutputerror ×4 · 98906cc8pixel e1046675PNG decode: PASSrejected · focal ring lostdiagonal-relaymaskoutputerror ×4 · 9e45deb5pixel f7aba567PNG decode: PASSaccepted · printable graingranite-quantizemaskoutputerror ×4 · c632f7b9pixel 22fc16c8PNG decode: PASSrejected · clipping dominatessign-loom
Four computed recipe editions
Each deterministic recipe card contains its actual coefficient mask, downsampled output, absolute-error view, pixel and error hashes, PNG validation state, and curator note.
Four deterministic recipe outputs from the pinned 128×96 fixture
RecipeActive coefficient maskOutput hashError hashPNG validationCurator note
quiet-horizon(0,3) (1,3) (2,3) (3,3) (4,3) (5,3) (6,3) (7,3) (0,4) (1,4) (2,4) (3,4) (4,4) (5,4) (6,4) (7,4) (0,5) (1,5) (2,5) (3,5) (4,5) (5,5) (6,5) (7,5) (0,6) (1,6) (2,6) (3,6) (4,6) (5,6) (6,6) (7,6) (0,7) (1,7) (2,7) (3,7) (4,7) (5,7) (6,7) (7,7)799662000ca54b81PASS: studio ImageBitmap decoded 128×96 PNGaccepted · restrained field
diagonal-relay(1,1) (2,2) (3,3) (4,4) (5,5) (6,6) (7,7)e104667598906cc8PASS: studio ImageBitmap decoded 128×96 PNGrejected · focal ring lost
granite-quantize(6,0) (7,0) (5,1) (6,1) (7,1) (4,2) (5,2) (6,2) (7,2) (3,3) (4,3) (5,3) (6,3) (7,3) (2,4) (3,4) (4,4) (5,4) (6,4) (7,4) (1,5) (2,5) (3,5) (4,5) (5,5) (6,5) (7,5) (0,6) (1,6) (2,6) (3,6) (4,6) (5,6) (6,6) (7,6) (0,7) (1,7) (2,7) (3,7) (4,7) (5,7) (6,7) (7,7)f7aba5679e45deb5PASS: studio ImageBitmap decoded 128×96 PNGaccepted · printable grain
sign-loom(3,0) (5,0) (7,0) (2,1) (4,1) (6,1) (1,2) (3,2) (5,2) (0,3) (2,3) (4,3) (1,4) (3,4) (0,5) (2,5) (1,6) (0,7)22fc16c8c632f7b9PASS: studio ImageBitmap decoded 128×96 PNGrejected · clipping dominates
Figure 3: The atlas preserves four real masks and pixel receipts; its accept/reject notes remain human art-direction judgments.

Export a valid image and its recipe

Serialize the final canvas through the browser’s PNG export path and verify that the blob can be decoded before enabling download. The Canvas bitmap-serialization algorithm defines the platform boundary. Store MIME type, byte length, decoded dimensions, and digest with the pixel receipt.

The DCT glitch art studio exports a new raster. It does not patch JPEG entropy-coded bytes, preserve original quantization tables, or claim encoder equivalence. If a JPEG deliverable is needed, feed the reconstructed pixels into an explicit encoder and record its settings as another stage.

Take one action: edit one coefficient band, inspect its error map, and publish the recipe with the image. Include source and output hashes, channel policy, normalization, edge handling, band energy, clip counts, and valid-export status. Revisit the edition if transform math, Canvas color/export behavior, gesture families, or print proofs change. The final work should look intentional even when its method celebrates damage.