{"id":"ascii-portrait","version":"1.0.0","title":"ASCII Portrait","summary":"A sculpted head made of thousands of glowing text characters decodes out of scrambled symbols, slowly turns, and types a caption underneath.","kind":"effect","target":"canvas2d","collections":["product-reveals","kinetic-text"],"tags":["ascii","ascii art","text art","terminal","portrait","characters","monospace","typewriter","decode","glitch","retro","hacker","matrix","green screen","crt","canvas","2d"],"loopable":false,"motion":"procedural","durationSeconds":8,"status":"published","media":{"poster":"https://aipixelwizard.com/media/ascii-portrait/1.0.0/poster.webp","preview":"https://aipixelwizard.com/media/ascii-portrait/1.0.0/preview.mp4","sample":"https://aipixelwizard.com/media/ascii-portrait/1.0.0/sample.mp4","sampleBytes":3859710,"sampleNote":"Pre-rendered with the default settings. Customised settings must be exported locally (npm run render)."},"urls":{"page":"https://aipixelwizard.com/visuals/ascii-portrait","manifest":"https://aipixelwizard.com/api/v1/visuals/ascii-portrait/versions/1.0.0","agentMd":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/agent.md","files":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/","demo":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/index.html"},"description":"The ASCII portrait look from this week's feeds: a picture redrawn with monospace characters, faint dots in the shadows and dense symbols in the light, like a terminal screen or a typewriter print. The demo is a classical marble bust that unscrambles out of random symbols, turns slowly under a moving light and then types a line of text with a blinking cursor. Change the characters (classic, code, binary or blocks), their size, the colours (green screen, amber, ink on paper), the glow and the caption. The renderer also works on anything already drawn on a canvas, so you can turn your own footage or 3D scene into text.","role":"Full-frame text-art effect (Canvas 2D) with its own subject; the renderer can also restyle any other layer.","useCases":["AI or tech product intro","Music video or lyric visual","Self-introduction or profile reel","Restyling your own footage as text"],"synonyms":["ascii effect","ascii video","ascii animation","ascii portrait","text portrait","character art","terminal art","typography portrait","made of letters","code face","ansi art","text mode","hacker text effect","decoding text effect"],"digest":"b3488dcd88c7cc37e069d1114241fc8bfe020404fae8963a241d888e62be9180","implementation":{"target":"canvas2d","runtime":"browser","language":"javascript","module":"esm","entry":"src/ascii-portrait.js","exports":[{"name":"createAscii","signature":"createAscii({ cellSize?, charset?, background?, ink?, dim?, contrast?, gamma?, glow?, fontFamily?, weight? }) => { grid(w, h), drawBuffer(ctx, w, h, buffer, opts?), drawField(ctx, w, h, field, opts?), applyToCanvas(ctx, w, h, opts?), caption(ctx, w, h, text, opts?), ramp, cellW, cellH }","description":"Canvas 2D character renderer. opts = { time, reveal: { start, duration, scramble } | null, clear }. caption() types text onto the same grid with a block cursor."},{"name":"CHARSETS","signature":"{ classic, code, binary, blocks }","description":"Built-in character sets; any string works too. Sorted at run time by measured ink coverage."},{"name":"createSculptedHead","signature":"createSculptedHead({ hair?, zoom?, offsetY? }) => { render(cols, rows, { yaw?, pitch?, aspect?, light?, background? }) => Float32Array }","description":"Ray-marched marble bust as a brightness buffer, one ray per character cell."}],"reusable":["src/ascii-portrait.js","src/sculpted-head.js"],"demo":"demo.js","harness":"index.html"},"dependencies":[{"id":"apw-runtime","version":"1.0.0","scope":"demo","reason":"Demo harness and easing. src/ascii-portrait.js and src/sculpted-head.js have no dependencies."}],"uses":[],"usedBy":[],"params":[{"key":"caption","label":"Caption","help":"Typed out under the portrait. Leave empty for no caption.","type":"text","default":"hello. i am made entirely of text.","maxLength":60,"sensitive":true},{"key":"charset","label":"Characters","type":"select","default":"classic","options":[{"value":"classic","label":"Classic ( . : + # @ )"},{"value":"code","label":"Code symbols ( { } / < > )"},{"value":"binary","label":"Binary ( 0 1 )"},{"value":"blocks","label":"Blocks ( ░ ▒ ▓ █ )"}]},{"key":"cellSize","label":"Character size","help":"Height of one character in pixels. Smaller shows more detail, larger reads more as text.","type":"number","min":8,"max":24,"step":1,"default":12},{"key":"ink","label":"Character colour","type":"color","default":"#5dffa0"},{"key":"background","label":"Background","help":"If it is lighter than the characters, the picture flips to ink on paper.","type":"color","default":"#020a05"},{"key":"glow","label":"Screen glow","help":"Soft bloom around bright characters. 0 for a clean print look.","type":"number","min":0,"max":1,"step":0.05,"default":0.55},{"key":"contrast","label":"Contrast","type":"number","min":0.6,"max":2,"step":0.05,"default":1.15},{"key":"decode","label":"Decode from scrambled symbols","help":"The portrait starts as random characters that settle into the image.","type":"boolean","default":true},{"key":"turn","label":"Head turn","help":"How far the head turns over the clip, in degrees.","type":"number","min":0,"max":90,"step":1,"default":40},{"key":"hair","label":"Carved hair","type":"boolean","default":true}],"presets":[{"id":"default","label":"Green terminal","params":{}},{"id":"paper","label":"Typewriter print","params":{"charset":"code","cellSize":10,"ink":"#1d1a16","background":"#eee6d3","glow":0.3,"contrast":1.25,"caption":"portrait no. 7, typed by machine"}},{"id":"amber","label":"Amber binary","params":{"charset":"binary","cellSize":13,"ink":"#ffb24a","background":"#140a02","glow":0.75,"turn":60,"caption":"01 identity loaded"}},{"id":"ice","label":"Ice blocks","params":{"charset":"blocks","cellSize":14,"ink":"#d9f1ff","background":"#050b16","glow":0.45,"hair":false,"decode":false,"caption":""}}],"output":{"width":1080,"height":1080,"fps":30,"durationSeconds":8,"posterSeconds":4,"alpha":false,"motion":"procedural","loop":{"seamless":false,"method":"A reveal: the portrait decodes in, turns once and the caption finishes typing; it ends on the finished portrait with a blinking cursor."},"seed":null},"composition":{"inputs":"2D canvas context, a brightness buffer (or function, or the canvas's own pixels) and info.time in seconds.","outputs":"Fills the canvas with the background colour and draws characters on it (pass clear: false to keep what is underneath). caption() draws on top.","coordinates":"A grid of characters centred in the frame; grid(width, height) gives cols, rows and cell size. Buffers are row-major, top row first.","lighting":"The bust has a key light from the upper left that swings with the turn, a rim light from behind and contact occlusion; brightness is mapped to character density.","timing":"Pure function of time and parameters. Decode is already under way on the first frame and settles by about 2 s; the caption starts typing at 1.5 s at 18 characters a second.","compatibleWith":["kinetic-title","vhs-camcorder","dither-animation","digital-rain","hologram"],"notes":["Caption text is treated as private and is not stored in shared packs unless you choose to include it.","Glyph shapes come from the viewer's monospace font. The character ramp is re-measured for whatever font is installed, so the tones stay right, but the exact look changes slightly between systems."]},"reuse":["Draw your own footage or any 3D ingredient onto a 2D canvas each frame, then call ascii.applyToCanvas to turn it into text (for example Chrome Material Orbit or Black Hole).","Use the decode reveal on its own as an intro: start with reveal.duration of 1 s over a logo drawn into a brightness buffer.","Swap the bust for another subject: anything that returns a brightness buffer works, including Dither Animation's moon scene.","Put Kinetic Title over the finished portrait for an end card, or run VHS Camcorder over it for a 1987 terminal."],"integration":{"newProject":"Create the renderer once with createAscii, get its grid, and each frame build a brightness buffer of cols × rows (createSculptedHead().render does this for the bust) and call drawBuffer, then caption.","existingProject":"Copy src/ascii-portrait.js. After you draw your frame on a 2D canvas (or copy a WebGL canvas onto one), call ascii.applyToCanvas(ctx, width, height, { time }) to redraw it as characters."},"performance":{"notes":"The character pass is one drawImage per cell from a pre-coloured glyph atlas plus one blur for the glow: a few milliseconds at 1080×1080. The ray-marched bust is the costly part: one ray per cell, roughly 20–40 ms a frame at the default size on a laptop, more with small characters.","limits":"Character sizes below 8 px get slow (the bust renders over 30,000 rays) and blur together on video. The caption is one line and is cut with an ellipsis if it is wider than the grid."},"limitations":["The bust is an idealised marble sculpture built from simple shapes, not a likeness of a real person; to turn a real face into text, draw your footage and use applyToCanvas.","Characters take one colour ramp from background to ink; per-character colour taken from a photo is not supported.","Monospace scripts only; the caption has no wrapping and no right-to-left shaping."],"license":{"spdx":"MIT","notice":"Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.","thirdParty":[]},"rights":{"approvedForPublicRelease":true},"provenance":"Original code written for AI Pixel Wizard on 2026-10-07 by an automated agent (the daily trend routine), inspired by the ASCII portrait trend in code-made AI video: @johnknopf's ASCII self-portrait (https://x.com/johnknopf/status/2103698854399099057, indexed at https://claudevideo.org/videos/ascii-character-portrait-types-out-a-self-introduction) and @cherry_mx_reds's neon-to-ASCII restyle (https://x.com/cherry_mx_reds/status/2105816670896009224). Techniques: brightness-to-character mapping and signed-distance ray marching are long-standing public techniques; the head is built from smooth-unioned ellipsoids and capsules written for this asset. The character ramp is measured from the installed font at run time; no fonts, images, models or code from elsewhere are included. Uses the viewer's monospace font; no font files are bundled.","changelog":[{"version":"1.0.0","date":"2026-10-07","notes":"Initial release."}],"verification":{"testedOn":"2026-10-10","inputs":{"ascii-portrait@1.0.0":"b3488dcd88c7cc37e069d1114241fc8bfe020404fae8963a241d888e62be9180","apw-runtime@1.0.0":"5be859cdac74823ba0bcc32c6daf06688a871104d24db5d4ceaffffd84d7c40d"},"environment":"Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0","renderer":"Canvas 2D","width":1080,"height":1080,"fps":30,"frames":240,"renderSeconds":94.9,"loopCheck":{"checked":false,"seamless":null,"maxDifference":null,"note":"Asset does not claim a seamless loop."},"determinism":{"checked":true,"identical":true},"errors":[],"media":{"poster":"/media/ascii-portrait/1.0.0/poster.webp","preview":"/media/ascii-portrait/1.0.0/preview.mp4","sample":"/media/ascii-portrait/1.0.0/sample.mp4","sampleBytes":3859710}},"files":[{"path":"LICENSE","size":1072,"sha256":"8a5f3a96f07e11522ec4bdd0a583356f99bad1245920f9709cee09b995a45153","contentType":"text/plain; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/LICENSE"},{"path":"asset.json","size":11759,"sha256":"e6ccf28f7d490fc42dab4e7ce7bca1449ed28f3adf40766bae2abe45e2f71fc3","contentType":"application/json; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/asset.json"},{"path":"demo.js","size":1951,"sha256":"bf8e359f6de0a0acbb95c5b54eccaab4191342f9b79e2093e637aa15e243758e","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/demo.js"},{"path":"index.html","size":528,"sha256":"dbe19839c89130dbea56a20ec724bf1c8b477a4c76b720d247f4d94abae0050c","contentType":"text/html; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/index.html"},{"path":"src/ascii-portrait.js","size":13917,"sha256":"af49000c1d605eeee71b2009a450b4ccb06bd4a3bbb9560d0b88d8aba7982f0c","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/src/ascii-portrait.js"},{"path":"src/sculpted-head.js","size":9295,"sha256":"2487a9a24da049fa069b410eb8a2a9a439673e39a244b575fcc705e468f2169b","contentType":"text/javascript; charset=utf-8","url":"https://aipixelwizard.com/registry/ascii-portrait/1.0.0/src/sculpted-head.js"}],"warnings":[]}