From cdd5c2b3b1ccfd88ddb049d3e05984e839f3c607 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 00:12:12 +0200 Subject: [PATCH 01/43] docs: updated textmode.js api docs --- .../classes/TextmodeCamera/accessors/eyeX.md | 77 +- .../classes/TextmodeCamera/accessors/eyeY.md | 73 +- .../classes/TextmodeCamera/accessors/eyeZ.md | 73 +- .../TextmodeCamera/accessors/targetX.md | 74 +- .../TextmodeCamera/accessors/targetY.md | 78 +- .../TextmodeCamera/accessors/targetZ.md | 84 +- .../classes/TextmodeCamera/accessors/upX.md | 75 +- .../classes/TextmodeCamera/accessors/upY.md | 82 +- .../classes/TextmodeCamera/accessors/upZ.md | 83 +- .../classes/TextmodeCamera/methods/copy.md | 97 +- .../classes/TextmodeCamera/methods/lookAt.md | 81 +- .../classes/TextmodeCamera/methods/move.md | 86 +- .../TextmodeCamera/methods/setPosition.md | 80 +- .../classes/TextmodeCamera/methods/setUp.md | 70 +- .../accessors/attachmentCount.md | 71 +- .../accessors/framebuffer.md | 70 +- .../TextmodeFramebuffer/accessors/height.md | 71 +- .../TextmodeFramebuffer/accessors/textures.md | 75 +- .../TextmodeFramebuffer/accessors/width.md | 68 +- .../TextmodeFramebuffer/methods/begin.md | 68 +- .../TextmodeFramebuffer/methods/dispose.md | 83 +- .../TextmodeFramebuffer/methods/end.md | 68 +- .../TextmodeFramebuffer/methods/readPixels.md | 93 +- .../TextmodeFramebuffer/methods/resize.md | 77 +- api/textmode.js/classes/TextmodeGlyphRamp.md | 354 +++++- api/textmode.js/classes/TextmodeGrid.md | 82 +- .../TextmodeGrid/accessors/cellHeight.md | 78 +- .../TextmodeGrid/accessors/cellWidth.md | 75 +- .../classes/TextmodeGrid/accessors/cols.md | 155 ++- .../classes/TextmodeGrid/accessors/height.md | 82 +- .../classes/TextmodeGrid/accessors/offsetX.md | 74 +- .../classes/TextmodeGrid/accessors/offsetY.md | 74 +- .../classes/TextmodeGrid/accessors/rows.md | 155 ++- .../classes/TextmodeGrid/accessors/width.md | 82 +- .../classes/TextmodeGrid/methods/reset.md | 84 +- .../TextmodeGrid/methods/responsive.md | 87 +- api/textmode.js/classes/TextmodeShader.md | 172 ++- api/textmode.js/classes/TextmodeVector.md | 95 +- .../classes/TextmodeVector/methods/add.md | 189 ++- .../classes/TextmodeVector/methods/copy.md | 94 +- .../classes/TextmodeVector/methods/cross.md | 189 ++- .../classes/TextmodeVector/methods/dist.md | 189 ++- .../classes/TextmodeVector/methods/div.md | 284 ++++- .../classes/TextmodeVector/methods/dot.md | 189 ++- .../classes/TextmodeVector/methods/heading.md | 94 +- .../classes/TextmodeVector/methods/limit.md | 94 +- .../classes/TextmodeVector/methods/mag.md | 94 +- .../classes/TextmodeVector/methods/magSq.md | 94 +- .../classes/TextmodeVector/methods/mult.md | 284 ++++- .../TextmodeVector/methods/normalize.md | 94 +- .../classes/TextmodeVector/methods/set.md | 189 ++- .../classes/TextmodeVector/methods/setMag.md | 94 +- .../classes/TextmodeVector/methods/sub.md | 189 ++- .../classes/Textmodifier/accessors/canvas.md | 80 +- .../Textmodifier/accessors/conversions.md | 47 +- .../classes/Textmodifier/accessors/errors.md | 69 +- .../classes/Textmodifier/accessors/filters.md | 47 +- .../classes/Textmodifier/accessors/font.md | 49 +- .../Textmodifier/accessors/frameCount.md | 101 +- .../classes/Textmodifier/accessors/grid.md | 46 +- .../classes/Textmodifier/accessors/height.md | 44 +- .../Textmodifier/accessors/isDisposed.md | 48 +- .../accessors/isRenderingFrame.md | 52 +- .../classes/Textmodifier/accessors/layers.md | 54 +- .../classes/Textmodifier/accessors/loading.md | 56 +- .../classes/Textmodifier/accessors/millis.md | 211 +++- .../classes/Textmodifier/accessors/overlay.md | 88 +- .../classes/Textmodifier/accessors/secs.md | 160 ++- .../classes/Textmodifier/accessors/width.md | 44 +- .../classes/Textmodifier/methods/abs.md | 71 +- .../classes/Textmodifier/methods/acos.md | 66 +- .../Textmodifier/methods/ambientLight.md | 54 +- .../Textmodifier/methods/applyMatrix.md | 52 +- .../classes/Textmodifier/methods/arc.md | 56 +- .../classes/Textmodifier/methods/asin.md | 64 +- .../classes/Textmodifier/methods/atan.md | 64 +- .../classes/Textmodifier/methods/atan2.md | 65 +- .../Textmodifier/methods/background.md | 198 ++- .../Textmodifier/methods/beginShape.md | 63 +- .../Textmodifier/methods/bezierCurve.md | 56 +- .../classes/Textmodifier/methods/box.md | 58 +- .../classes/Textmodifier/methods/camera.md | 55 +- .../classes/Textmodifier/methods/ceil.md | 60 +- .../classes/Textmodifier/methods/cellColor.md | 196 ++- .../classes/Textmodifier/methods/char.md | 96 +- .../classes/Textmodifier/methods/charColor.md | 198 ++- .../Textmodifier/methods/charRotation.md | 53 +- .../classes/Textmodifier/methods/clamp.md | 93 +- .../classes/Textmodifier/methods/clear.md | 57 +- .../classes/Textmodifier/methods/color.md | 154 ++- .../classes/Textmodifier/methods/colorMode.md | 293 ++++- .../classes/Textmodifier/methods/cone.md | 58 +- .../classes/Textmodifier/methods/constrain.md | 91 +- .../classes/Textmodifier/methods/cos.md | 64 +- .../Textmodifier/methods/createCamera.md | 59 +- .../methods/createFilterShader.md | 77 +- .../Textmodifier/methods/createFramebuffer.md | 51 +- .../Textmodifier/methods/createGlyphRamp.md | 58 +- .../methods/createMaterialShader.md | 77 +- .../Textmodifier/methods/createShader.md | 66 +- .../Textmodifier/methods/createTexture.md | 56 +- .../Textmodifier/methods/createVector.md | 94 +- .../classes/Textmodifier/methods/cursor.md | 98 +- .../classes/Textmodifier/methods/cylinder.md | 58 +- .../classes/Textmodifier/methods/degrees.md | 79 +- .../classes/Textmodifier/methods/deltaTime.md | 56 +- .../classes/Textmodifier/methods/destroy.md | 51 +- .../classes/Textmodifier/methods/dist.md | 75 +- .../Textmodifier/methods/doubleClicked.md | 72 +- .../classes/Textmodifier/methods/doubleTap.md | 73 +- .../classes/Textmodifier/methods/draw.md | 50 +- .../classes/Textmodifier/methods/ease.md | 79 +- .../classes/Textmodifier/methods/ellipse.md | 55 +- .../classes/Textmodifier/methods/ellipsoid.md | 58 +- .../classes/Textmodifier/methods/endShape.md | 63 +- .../Textmodifier/methods/exitPointerLock.md | 94 +- .../classes/Textmodifier/methods/exp.md | 65 +- .../classes/Textmodifier/methods/fill.md | 195 ++- .../classes/Textmodifier/methods/filter.md | 91 +- .../classes/Textmodifier/methods/flipX.md | 57 +- .../classes/Textmodifier/methods/flipY.md | 57 +- .../classes/Textmodifier/methods/floor.md | 65 +- .../classes/Textmodifier/methods/fontSize.md | 48 +- .../classes/Textmodifier/methods/fract.md | 61 +- .../classes/Textmodifier/methods/frameRate.md | 57 +- .../classes/Textmodifier/methods/gamepad.md | 53 +- .../methods/gamepadAxisChanged.md | 58 +- .../methods/gamepadButtonPressed.md | 57 +- .../methods/gamepadButtonReleased.md | 57 +- .../Textmodifier/methods/gamepadConnected.md | 57 +- .../methods/gamepadDisconnected.md | 57 +- .../classes/Textmodifier/methods/image.md | 52 +- .../classes/Textmodifier/methods/inputGrid.md | 67 +- .../classes/Textmodifier/methods/invert.md | 61 +- .../Textmodifier/methods/isKeyPressed.md | 98 +- .../classes/Textmodifier/methods/isLooping.md | 56 +- .../Textmodifier/methods/keyPressed.md | 96 +- .../Textmodifier/methods/keyReleased.md | 95 +- .../classes/Textmodifier/methods/keyTyped.md | 90 +- .../classes/Textmodifier/methods/lerp.md | 81 +- .../Textmodifier/methods/lightFalloff.md | 53 +- .../classes/Textmodifier/methods/line.md | 57 +- .../Textmodifier/methods/lineWeight.md | 53 +- .../classes/Textmodifier/methods/loadFont.md | 86 +- .../classes/Textmodifier/methods/loadImage.md | 49 +- .../Textmodifier/methods/loadTileset.md | 62 +- .../classes/Textmodifier/methods/loadVideo.md | 49 +- .../classes/Textmodifier/methods/log.md | 65 +- .../classes/Textmodifier/methods/longPress.md | 73 +- .../classes/Textmodifier/methods/lookAt.md | 59 +- .../classes/Textmodifier/methods/loop.md | 49 +- .../classes/Textmodifier/methods/map.md | 66 +- .../classes/Textmodifier/methods/max.md | 125 +- .../classes/Textmodifier/methods/min.md | 125 +- .../Textmodifier/methods/mouseClicked.md | 84 +- .../Textmodifier/methods/mouseDragged.md | 91 +- .../Textmodifier/methods/mouseMoved.md | 87 +- .../Textmodifier/methods/mousePressed.md | 86 +- .../Textmodifier/methods/mouseReleased.md | 98 +- .../Textmodifier/methods/mouseScrolled.md | 86 +- .../classes/Textmodifier/methods/noLights.md | 53 +- .../classes/Textmodifier/methods/noLoop.md | 59 +- .../classes/Textmodifier/methods/noTexture.md | 88 +- .../classes/Textmodifier/methods/noise.md | 58 +- .../Textmodifier/methods/noiseDetail.md | 61 +- .../classes/Textmodifier/methods/noiseSeed.md | 60 +- .../classes/Textmodifier/methods/norm.md | 64 +- .../classes/Textmodifier/methods/ortho.md | 52 +- .../Textmodifier/methods/perspective.md | 54 +- .../classes/Textmodifier/methods/pinch.md | 57 +- .../Textmodifier/methods/pixelDensity.md | 169 ++- .../classes/Textmodifier/methods/point.md | 52 +- .../Textmodifier/methods/pointLight.md | 54 +- .../classes/Textmodifier/methods/pop.md | 52 +- .../classes/Textmodifier/methods/pow.md | 61 +- .../classes/Textmodifier/methods/print.md | 69 +- .../Textmodifier/methods/printAlign.md | 96 +- .../classes/Textmodifier/methods/push.md | 54 +- .../classes/Textmodifier/methods/radians.md | 73 +- .../classes/Textmodifier/methods/random.md | 239 +++- .../Textmodifier/methods/randomGaussian.md | 80 +- .../Textmodifier/methods/randomSeed.md | 66 +- .../Textmodifier/methods/randomStream.md | 59 +- .../classes/Textmodifier/methods/rect.md | 56 +- .../classes/Textmodifier/methods/redraw.md | 76 +- .../methods/requestPointerLock.md | 94 +- .../Textmodifier/methods/resetCamera.md | 53 +- .../Textmodifier/methods/resetMatrix.md | 54 +- .../Textmodifier/methods/resetShader.md | 69 +- .../Textmodifier/methods/resizeCanvas.md | 51 +- .../classes/Textmodifier/methods/rotate.md | 73 +- .../Textmodifier/methods/rotateGesture.md | 61 +- .../classes/Textmodifier/methods/rotateX.md | 55 +- .../classes/Textmodifier/methods/rotateY.md | 55 +- .../classes/Textmodifier/methods/rotateZ.md | 55 +- .../classes/Textmodifier/methods/round.md | 66 +- .../classes/Textmodifier/methods/scale.md | 73 +- .../classes/Textmodifier/methods/setCamera.md | 66 +- .../Textmodifier/methods/setUniform.md | 71 +- .../Textmodifier/methods/setUniforms.md | 70 +- .../classes/Textmodifier/methods/setup.md | 56 +- .../classes/Textmodifier/methods/shader.md | 72 +- .../classes/Textmodifier/methods/sin.md | 69 +- .../classes/Textmodifier/methods/sphere.md | 58 +- .../classes/Textmodifier/methods/sq.md | 64 +- .../classes/Textmodifier/methods/sqrt.md | 66 +- .../classes/Textmodifier/methods/stroke.md | 195 ++- .../classes/Textmodifier/methods/swipe.md | 81 +- .../classes/Textmodifier/methods/tan.md | 66 +- .../classes/Textmodifier/methods/tap.md | 73 +- .../Textmodifier/methods/targetFrameRate.md | 53 +- .../classes/Textmodifier/methods/texture.md | 76 +- .../classes/Textmodifier/methods/torus.md | 58 +- .../Textmodifier/methods/touchCancelled.md | 73 +- .../Textmodifier/methods/touchEnded.md | 73 +- .../Textmodifier/methods/touchMoved.md | 73 +- .../Textmodifier/methods/touchStarted.md | 73 +- .../classes/Textmodifier/methods/translate.md | 55 +- .../Textmodifier/methods/translateX.md | 156 ++- .../Textmodifier/methods/translateY.md | 145 ++- .../Textmodifier/methods/translateZ.md | 124 +- .../classes/Textmodifier/methods/triangle.md | 50 +- .../Textmodifier/methods/useTileColors.md | 48 +- .../classes/Textmodifier/methods/vertex.md | 90 +- .../Textmodifier/methods/windowResized.md | 50 +- .../Textmodifier/properties/BLEND_ADDITIVE.md | 77 +- .../properties/BLEND_COLOR_BURN.md | 77 +- .../properties/BLEND_COLOR_DODGE.md | 77 +- .../Textmodifier/properties/BLEND_DARKEN.md | 77 +- .../properties/BLEND_DIFFERENCE.md | 77 +- .../properties/BLEND_EXCLUSION.md | 77 +- .../properties/BLEND_HARD_LIGHT.md | 77 +- .../Textmodifier/properties/BLEND_LIGHTEN.md | 77 +- .../Textmodifier/properties/BLEND_MULTIPLY.md | 77 +- .../Textmodifier/properties/BLEND_NORMAL.md | 78 +- .../Textmodifier/properties/BLEND_OVERLAY.md | 77 +- .../Textmodifier/properties/BLEND_SCREEN.md | 77 +- .../properties/BLEND_SOFT_LIGHT.md | 77 +- .../Textmodifier/properties/BLEND_SUBTRACT.md | 77 +- .../classes/Textmodifier/properties/LINES.md | 56 +- .../Textmodifier/properties/LINE_LOOP.md | 55 +- .../Textmodifier/properties/LINE_STRIP.md | 55 +- .../classes/Textmodifier/properties/POINTS.md | 54 +- .../classes/Textmodifier/properties/QUADS.md | 60 +- .../Textmodifier/properties/QUAD_STRIP.md | 57 +- .../Textmodifier/properties/TRIANGLES.md | 58 +- .../Textmodifier/properties/TRIANGLE_FAN.md | 59 +- .../Textmodifier/properties/TRIANGLE_STRIP.md | 56 +- .../Textmodifier/properties/displayHeight.md | 74 +- .../Textmodifier/properties/displayWidth.md | 74 +- .../Textmodifier/properties/gamepads.md | 51 +- .../Textmodifier/properties/lastKeyPressed.md | 84 +- .../properties/lastKeyReleased.md | 86 +- .../Textmodifier/properties/modifierState.md | 54 +- .../classes/Textmodifier/properties/mouse.md | 62 +- .../Textmodifier/properties/mouseIsPressed.md | 87 +- .../classes/Textmodifier/properties/movedX.md | 94 +- .../classes/Textmodifier/properties/movedY.md | 94 +- .../classes/Textmodifier/properties/pmouse.md | 98 +- .../Textmodifier/properties/pressedKeys.md | 93 +- .../Textmodifier/properties/touches.md | 58 +- .../Textmodifier/properties/windowHeight.md | 78 +- .../Textmodifier/properties/windowWidth.md | 78 +- api/textmode.js/classes/textmode.md | 74 +- .../classes/textmode/accessors/version.md | 96 +- .../classes/textmode/methods/create.md | 67 +- .../classes/textmode/methods/setErrorLevel.md | 98 +- .../enumerations/ShapeAssemblyMode.md | 510 +++++++- .../namespaces/color/classes/TextmodeColor.md | 87 +- .../TextmodeColor/accessors/normalized.md | 75 +- .../classes/TextmodeColor/accessors/rgb.md | 86 +- .../classes/TextmodeColor/accessors/rgba.md | 98 +- .../TextmodeColor/methods/withAlpha.md | 55 +- .../classes/TextmodeColor/properties/a.md | 94 +- .../classes/TextmodeColor/properties/b.md | 75 +- .../classes/TextmodeColor/properties/g.md | 73 +- .../classes/TextmodeColor/properties/r.md | 78 +- .../classes/TextmodeConversionManager.md | 173 ++- .../interfaces/TextmodeConversionContext.md | 90 +- .../interfaces/TextmodeConversionStrategy.md | 173 ++- .../filters/classes/TextmodeFilterManager.md | 172 ++- .../namespaces/fonts/classes/TextmodeFont.md | 87 +- .../TextmodeFont/accessors/characterMap.md | 79 +- .../TextmodeFont/accessors/characters.md | 79 +- .../classes/TextmodeFont/accessors/font.md | 72 +- .../TextmodeFont/accessors/fontSize.md | 71 +- .../TextmodeFont/accessors/framebuffer.md | 74 +- .../accessors/maxGlyphDimensions.md | 70 +- .../TextmodeFont/accessors/textureColumns.md | 68 +- .../TextmodeFont/accessors/textureRows.md | 68 +- .../classes/TextmodeFont/methods/dispose.md | 98 +- .../fonts/classes/TextmodeTileset.md | 74 +- .../accessors/cellDimensions.md | 88 +- .../TextmodeTileset/accessors/cellHeight.md | 87 +- .../TextmodeTileset/accessors/cellWidth.md | 87 +- .../TextmodeTileset/accessors/characterMap.md | 87 +- .../TextmodeTileset/accessors/characters.md | 93 +- .../TextmodeTileset/accessors/columns.md | 88 +- .../accessors/fontFramebuffer.md | 74 +- .../TextmodeTileset/accessors/fontSize.md | 90 +- .../TextmodeTileset/accessors/framebuffer.md | 93 +- .../accessors/maxGlyphDimensions.md | 87 +- .../accessors/nativeCellDimensions.md | 89 +- .../classes/TextmodeTileset/accessors/rows.md | 89 +- .../accessors/textureColumns.md | 87 +- .../TextmodeTileset/accessors/textureRows.md | 88 +- .../TextmodeTileset/methods/dispose.md | 96 +- .../accessors/asciiFramebuffer.md | 63 +- .../accessors/drawFramebuffer.md | 74 +- .../classes/TextmodeLayer/accessors/font.md | 76 +- .../classes/TextmodeLayer/accessors/grid.md | 63 +- .../classes/TextmodeLayer/accessors/height.md | 56 +- .../TextmodeLayer/accessors/texture.md | 59 +- .../classes/TextmodeLayer/accessors/width.md | 56 +- .../TextmodeLayer/methods/blendMode.md | 88 +- .../classes/TextmodeLayer/methods/camera.md | 93 +- .../TextmodeLayer/methods/createCamera.md | 97 +- .../methods/deletePluginState.md | 76 +- .../classes/TextmodeLayer/methods/draw.md | 85 +- .../classes/TextmodeLayer/methods/filter.md | 82 +- .../classes/TextmodeLayer/methods/fontSize.md | 71 +- .../TextmodeLayer/methods/getPluginState.md | 86 +- .../TextmodeLayer/methods/hasPluginState.md | 72 +- .../classes/TextmodeLayer/methods/hide.md | 99 +- .../TextmodeLayer/methods/loadTileset.md | 93 +- .../classes/TextmodeLayer/methods/lookAt.md | 93 +- .../classes/TextmodeLayer/methods/offset.md | 79 +- .../classes/TextmodeLayer/methods/opacity.md | 86 +- .../classes/TextmodeLayer/methods/ortho.md | 85 +- .../TextmodeLayer/methods/perspective.md | 92 +- .../TextmodeLayer/methods/resetCamera.md | 94 +- .../classes/TextmodeLayer/methods/rotateZ.md | 74 +- .../TextmodeLayer/methods/setCamera.md | 97 +- .../TextmodeLayer/methods/setPluginState.md | 81 +- .../classes/TextmodeLayer/methods/show.md | 78 +- .../TextmodeLayer/methods/useTileColors.md | 97 +- .../TextmodeLayerManager/accessors/all.md | 72 +- .../TextmodeLayerManager/accessors/base.md | 92 +- .../TextmodeLayerManager/accessors/filters.md | 99 +- .../accessors/resultFramebuffer.md | 94 +- .../TextmodeLayerManager/methods/add.md | 91 +- .../TextmodeLayerManager/methods/clear.md | 99 +- .../TextmodeLayerManager/methods/move.md | 97 +- .../TextmodeLayerManager/methods/remove.md | 97 +- .../TextmodeLayerManager/methods/swap.md | 99 +- .../layering/enumerations/LayerBlendMode.md | 1079 ++++++++++++++++- .../namespaces/media/classes/TextmodeImage.md | 82 +- .../classes/TextmodeImage/accessors/height.md | 76 +- .../TextmodeImage/accessors/originalHeight.md | 76 +- .../TextmodeImage/accessors/originalWidth.md | 76 +- .../TextmodeImage/accessors/texture.md | 76 +- .../classes/TextmodeImage/accessors/width.md | 76 +- .../TextmodeImage/methods/background.md | 92 +- .../TextmodeImage/methods/brightnessRange.md | 87 +- .../TextmodeImage/methods/cellColor.md | 66 +- .../TextmodeImage/methods/cellColorMode.md | 70 +- .../TextmodeImage/methods/charColor.md | 65 +- .../TextmodeImage/methods/charColorMode.md | 70 +- .../TextmodeImage/methods/charRotation.md | 66 +- .../TextmodeImage/methods/characters.md | 77 +- .../TextmodeImage/methods/clearConversions.md | 77 +- .../TextmodeImage/methods/conversionMode.md | 54 +- .../TextmodeImage/methods/conversions.md | 96 +- .../classes/TextmodeImage/methods/dispose.md | 84 +- .../classes/TextmodeImage/methods/flipX.md | 70 +- .../classes/TextmodeImage/methods/flipY.md | 70 +- .../classes/TextmodeImage/methods/invert.md | 66 +- .../TextmodeSource/accessors/height.md | 75 +- .../accessors/originalHeight.md | 75 +- .../TextmodeSource/accessors/originalWidth.md | 75 +- .../TextmodeSource/accessors/texture.md | 75 +- .../classes/TextmodeSource/accessors/width.md | 75 +- .../TextmodeSource/methods/background.md | 91 +- .../TextmodeSource/methods/brightnessRange.md | 86 +- .../TextmodeSource/methods/cellColor.md | 65 +- .../TextmodeSource/methods/cellColorMode.md | 69 +- .../TextmodeSource/methods/charColor.md | 64 +- .../TextmodeSource/methods/charColorMode.md | 69 +- .../TextmodeSource/methods/charRotation.md | 65 +- .../TextmodeSource/methods/characters.md | 76 +- .../methods/clearConversions.md | 76 +- .../TextmodeSource/methods/conversionMode.md | 53 +- .../TextmodeSource/methods/conversions.md | 95 +- .../classes/TextmodeSource/methods/dispose.md | 84 +- .../classes/TextmodeSource/methods/flipX.md | 69 +- .../classes/TextmodeSource/methods/flipY.md | 69 +- .../classes/TextmodeSource/methods/invert.md | 65 +- .../TextmodeTexture/accessors/height.md | 76 +- .../accessors/originalHeight.md | 76 +- .../accessors/originalWidth.md | 76 +- .../TextmodeTexture/accessors/source.md | 62 +- .../TextmodeTexture/accessors/texture.md | 76 +- .../TextmodeTexture/accessors/width.md | 76 +- .../TextmodeTexture/methods/background.md | 92 +- .../methods/brightnessRange.md | 87 +- .../TextmodeTexture/methods/cellColor.md | 66 +- .../TextmodeTexture/methods/cellColorMode.md | 70 +- .../TextmodeTexture/methods/charColor.md | 65 +- .../TextmodeTexture/methods/charColorMode.md | 70 +- .../TextmodeTexture/methods/charRotation.md | 66 +- .../TextmodeTexture/methods/characters.md | 77 +- .../methods/clearConversions.md | 77 +- .../TextmodeTexture/methods/conversionMode.md | 54 +- .../TextmodeTexture/methods/conversions.md | 96 +- .../TextmodeTexture/methods/dispose.md | 84 +- .../classes/TextmodeTexture/methods/flipX.md | 70 +- .../classes/TextmodeTexture/methods/flipY.md | 70 +- .../classes/TextmodeTexture/methods/invert.md | 66 +- .../namespaces/media/classes/TextmodeVideo.md | 55 +- .../TextmodeVideo/accessors/currentTime.md | 56 +- .../TextmodeVideo/accessors/duration.md | 88 +- .../classes/TextmodeVideo/accessors/height.md | 76 +- .../TextmodeVideo/accessors/isPlaying.md | 74 +- .../TextmodeVideo/accessors/originalHeight.md | 76 +- .../TextmodeVideo/accessors/originalWidth.md | 76 +- .../classes/TextmodeVideo/accessors/source.md | 63 +- .../TextmodeVideo/accessors/texture.md | 76 +- .../TextmodeVideo/accessors/videoElement.md | 72 +- .../classes/TextmodeVideo/accessors/width.md | 76 +- .../TextmodeVideo/methods/background.md | 92 +- .../TextmodeVideo/methods/brightnessRange.md | 87 +- .../TextmodeVideo/methods/cellColor.md | 66 +- .../TextmodeVideo/methods/cellColorMode.md | 70 +- .../TextmodeVideo/methods/charColor.md | 65 +- .../TextmodeVideo/methods/charColorMode.md | 70 +- .../TextmodeVideo/methods/charRotation.md | 66 +- .../TextmodeVideo/methods/characters.md | 77 +- .../TextmodeVideo/methods/clearConversions.md | 77 +- .../TextmodeVideo/methods/conversionMode.md | 54 +- .../TextmodeVideo/methods/conversions.md | 96 +- .../classes/TextmodeVideo/methods/dispose.md | 69 +- .../classes/TextmodeVideo/methods/flipX.md | 70 +- .../classes/TextmodeVideo/methods/flipY.md | 70 +- .../classes/TextmodeVideo/methods/invert.md | 66 +- .../classes/TextmodeVideo/methods/loop.md | 70 +- .../classes/TextmodeVideo/methods/pause.md | 73 +- .../classes/TextmodeVideo/methods/play.md | 71 +- .../classes/TextmodeVideo/methods/speed.md | 67 +- .../classes/TextmodeVideo/methods/stop.md | 78 +- .../classes/TextmodeVideo/methods/time.md | 70 +- .../classes/TextmodeVideo/methods/volume.md | 80 +- .../plugins/interfaces/TextmodePlugin.md | 150 ++- .../methods/registerLayerDisposedHook.md | 72 +- .../methods/registerLayerPostRenderHook.md | 53 +- .../methods/registerLayerPreRenderHook.md | 53 +- .../methods/registerPostDrawHook.md | 81 +- .../methods/registerPostSetupHook.md | 53 +- .../methods/registerPreDrawHook.md | 83 +- .../methods/registerPreSetupHook.md | 86 +- .../methods/removeLayerExtension.md | 86 +- 450 files changed, 37486 insertions(+), 528 deletions(-) diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md index 1870f061..0f5b571e 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md @@ -28,5 +28,80 @@ Current X position of the camera eye. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let eyeXVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawScene(tm, sweepX) { + t.push(); + t.ambientLight(30, 40, 70); + t.pointLight(255, 200, 150, sweepX * 0.5, 16, 20); + + for (let x = -24; x <= 24; x += 8) { + for (let z = -24; z <= 24; z += 8) { + const h = Math.floor((Math.sin(x * 0.15 + z * 0.15 + tm) * 0.5 + 0.5) * 12 + 4); + t.push(); + t.translate(x, h * 0.5, z); + t.charColor(Math.floor(80 + (x + 24) * 3.5), 180, Math.floor(240 - (z + 24) * 3.5)); + t.cellColor(10, 18, 32); + t.char('#'); + t.box(4, h, 4); + t.pop(); + } + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 24); + const tm = t.frameCount * 0.04; + const sweepX = Math.sin(tm) * 32; + + const cam = t.createCamera().setPosition(sweepX, 14, 38).lookAt(0, 4, 0); + + eyeXVal = cam.eyeX; + t.setCamera(cam); + drawScene(tm, sweepX); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.EYEX', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: LIT MONOLITH LATERAL SWEEP', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera eye X world coordinate.', x, y++); + t.print('Point light illuminates 3D monoliths.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`EYE X: ${eyeXVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md index 05b11a63..ad6855d3 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md @@ -28,5 +28,76 @@ Current Y position of the camera eye. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let eyeYVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawTerrarium(tm) { + t.push(); + for (let ring = 4; ring >= 1; ring--) { + const s = ring * 6; + const h = (5 - ring) * 3; + t.push(); + t.translate(0, h * 0.5, 0); + t.charColor(Math.floor(240 - ring * 35), Math.floor(140 + ring * 25), Math.floor(80 + ring * 30)); + t.cellColor(20, 10, 16); + t.char('#'); + t.box(s, 2.5, s); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(12, 6, 18); + const tm = t.frameCount * 0.04; + const altitudeY = Math.sin(tm) * 24 + 18; + + const cam = t.createCamera().setPosition(0, altitudeY, 36).lookAt(0, 4, 0); + + eyeYVal = cam.eyeY; + t.setCamera(cam); + drawTerrarium(tm); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.EYEY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ALTITUDE OVERFLIGHT OVERVIEW', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera eye Y world coordinate.', x, y++); + t.print('Eye sweeps vertically over terrarium.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`EYE Y: ${eyeYVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md index a652c74f..31cd374d 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md @@ -28,5 +28,76 @@ Current Z position of the camera eye. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let eyeZVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawTunnel(tm) { + t.push(); + for (let i = 0; i < 10; i++) { + const zPos = i * -12; + const s = 12 + i * 2; + t.push(); + t.translate(0, 0, zPos); + t.charColor(Math.floor(80 + i * 15), Math.floor(120 + i * 12), Math.floor(255 - i * 18)); + t.cellColor(12, 8, 24); + t.char('#'); + t.box(s, s, 2); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(10, 6, 20); + const tm = t.frameCount * 0.04; + const zoomZ = Math.cos(tm) * 40 + 50; + + const cam = t.createCamera().setPosition(0, 0, zoomZ).lookAt(0, 0, -40); + + eyeZVal = cam.eyeZ; + t.setCamera(cam); + drawTunnel(tm); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.EYEZ', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: DEPTH ZOOM TUNNEL CORRIDOR', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera eye Z world coordinate.', x, y++); + t.print('Eye zooms forward/backward on Z axis.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`EYE Z: ${eyeZVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md index 9205ed4c..cd96165f 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md @@ -28,5 +28,77 @@ Current X position of the camera target. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let targetXVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawAltars(panX) { + t.push(); + t.ambientLight(25, 45, 30); + t.pointLight(120, 240, 255, panX, 12, 10); + + for (let x = -20; x <= 20; x += 10) { + t.push(); + t.translate(x, 4, 0); + t.charColor(Math.floor(100 + (x + 20) * 3.5), 240, 180); + t.cellColor(8, 24, 16); + t.char('#'); + t.box(5, 8, 5); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(4, 14, 10); + const tm = t.frameCount * 0.04; + const panX = Math.sin(tm) * 24; + + const cam = t.createCamera().setPosition(0, 12, 36).lookAt(panX, 4, 0); + + targetXVal = cam.targetX; + t.setCamera(cam); + drawAltars(panX); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.TARGETX', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: LIT 3D ALTAR PAN SCANNER', x, y++); + t.charColor(140, 160, 190); + t.print('Reads look-at target X coordinate.', x, y++); + t.print('Point light tracks target across altars.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TARGET X: ${targetXVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md index 919e810d..57c9ccec 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md @@ -28,5 +28,81 @@ Current Y position of the camera target. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let targetYVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawAttractorAltars(panY) { + t.push(); + t.ambientLight(25, 30, 45); + t.pointLight(255, 210, 60, 0, panY, 12); + + for (let i = -6; i <= 6; i++) { + const y = i * 4; + const x = Math.sin(i * 0.5) * 12; + const z = Math.cos(i * 0.5) * 8; + + t.push(); + t.translate(x, y, z); + t.charColor(Math.floor(80 + (i + 6) * 14), 255, 160); + t.cellColor(25, 10, 35); + t.char('#'); + t.box(6, 3, 6); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(12, 6, 24); + const tm = t.frameCount * 0.04; + const panY = Math.sin(tm) * 18; + + const cam = t.createCamera().setPosition(28, 4, 32).lookAt(0, panY, 0); + + targetYVal = cam.targetY; + t.setCamera(cam); + drawAttractorAltars(panY); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.TARGETY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: AIZAWA 3D ALTAR PAN SCAN', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera lookAt target Y coord.', x, y++); + t.print('Point light tracks vertical Y target.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 210, 60); + t.print(`TARGET Y: ${targetYVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md index 3e3b3f58..8200c739 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md @@ -28,5 +28,87 @@ Current Z position of the camera target. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let targetDepth = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawSubaquaticTunnel(tz) { + t.push(); + t.ambientLight(15, 30, 45); + t.pointLight(0, 220, 240, 0, 0, tz); + + for (let z = -28; z <= 28; z += 7) { + t.push(); + t.translate(0, 0, z); + const dist = Math.abs(z - tz); + const bright = Math.max(0, 1 - dist / 20); + t.charColor(Math.floor(20 + bright * 80), Math.floor(140 + bright * 115), Math.floor(180 + bright * 75)); + t.cellColor(4, 16, 28); + t.char(dist < 5 ? 'O' : 'o'); + t.ellipse(14, 10); + t.pop(); + } + + t.push(); + t.translate(0, 0, tz); + t.charColor(140, 255, 240); + t.cellColor(10, 40, 60); + t.char('*'); + t.box(4, 4, 1); + t.pop(); + t.pop(); +} + +t.draw(() => { + t.background(4, 12, 22); + const tm = t.frameCount * 0.03; + const tz = Math.sin(tm) * 20; + + const cam = t.createCamera().setPosition(18, 12, 38).lookAt(0, 0, tz); + targetDepth = cam.targetZ; + + t.setCamera(cam); + drawSubaquaticTunnel(tz); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 220); + t.print('TEXTMODECAMERA.TARGETZ', x, y++); + t.charColor(60, 90, 130); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SUBAQUATIC DEPTH SCANNER', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera look-at Z target.', x, y++); + t.print('Point light tracks focal depth ring.', x, y++); + t.charColor(60, 90, 130); + t.print('------------------------------------', x, y++); + t.charColor(120, 255, 220); + t.print(`TARGET Z: ${targetDepth.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md index 5ca77ba8..bed93f89 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md @@ -28,5 +28,78 @@ Current X component of the camera up vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let upXVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawHorizon() { + t.push(); + t.char('.'); + t.charColor(60, 100, 180); + for (let x = -24; x <= 24; x += 6) { + for (let z = -24; z <= 24; z += 6) { + t.push(); + t.translate(x, 0, z); + t.charColor(x === 0 ? 255 : 80, 220, z === 0 ? 255 : 140); + t.cellColor(10, 14, 28); + t.char('+'); + t.box(4, 0.5, 4); + t.pop(); + } + } + t.pop(); +} + +t.draw(() => { + t.background(10, 10, 24); + const tm = t.frameCount * 0.04; + const rollX = Math.sin(tm); + + const cam = t.createCamera().setPosition(0, 12, 32).lookAt(0, 0, 0).setUp(rollX, 1, 0); + + upXVal = cam.upX; + t.setCamera(cam); + drawHorizon(); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.UPX', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ROLLING FLIGHT HORIZON', x, y++); + t.charColor(140, 160, 190); + t.print('Reads up-vector X component.', x, y++); + t.print('Modulating upX rolls camera view.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`UP X: ${upXVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md index 4908ca6a..9aea8052 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md @@ -28,5 +28,85 @@ Current Y component of the camera up vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ['.', ':', '=', '#', '%']; +const labelLayer = t.layers.add(); +let upVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawScene(tm) { + t.push(); + t.ambientLight(25, 35, 60); + t.pointLight(255, 200, 140, Math.sin(tm) * 20, 18, 25); + + for (let x = -24; x <= 24; x += 8) { + for (let z = -24; z <= 24; z += 8) { + const norm = Math.sin(x * 0.15 + z * 0.15 + tm) * 0.5 + 0.5; + const h = Math.floor(norm * 12 + 4); + const rIdx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); + + t.push(); + t.translate(x, h * 0.5, z); + t.charColor(Math.floor(40 + norm * 140), Math.floor(160 + norm * 80), Math.floor(220 - norm * 60)); + t.cellColor(10, 18, 36); + t.char(RAMP[rIdx]); + t.box(4, h, 4); + t.pop(); + } + } + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 24); + const tm = t.frameCount * 0.03; + const rollY = Math.sin(tm * 0.8) * 1.5; + + const cam = t.createCamera().setPosition(36, 12, 36).lookAt(0, 2, 0); + cam.setUp(0, rollY, 1); + + upVal = cam.upY; + t.setCamera(cam); + drawScene(tm); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.UPY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: GYROSCOPIC HORIZON SWEEP', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera up vector Y component.', x, y++); + t.print('Oscillating upY banks world horizon.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`UP Y VALUE: ${upVal.toFixed(3)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md index 6f6b60a7..1dcc45c2 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md @@ -28,5 +28,86 @@ Current Z component of the camera up vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let upZVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawHelixVortex(tm) { + t.push(); + t.ambientLight(30, 15, 30); + t.pointLight(255, 50, 150, 0, 0, 16); + + for (let i = -12; i <= 12; i++) { + const angle = i * 0.4 + tm * 2; + const x = Math.cos(angle) * 14; + const y = Math.sin(angle) * 14; + const z = i * 2; + + t.push(); + t.translate(x, y, z); + t.charColor(255, Math.floor(50 + (i + 12) * 8), Math.floor(150 - (i + 12) * 4)); + t.cellColor(30, 8, 25); + t.char('O'); + t.box(3, 3, 3); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(24, 6, 20); + const tm = t.frameCount * 0.04; + const tiltZ = Math.sin(tm) * 0.8; + + const cam = t + .createCamera() + .setPosition(0, 0, 42) + .lookAt(0, 0, 0) + .setUp(0, Math.cos(tm) * 0.8, tiltZ); + + upZVal = cam.upZ; + t.setCamera(cam); + drawHelixVortex(tm); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.UPZ', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HELICAL VORTEX Z-AXIS ROTOR', x, y++); + t.charColor(140, 160, 190); + t.print('Reads camera up-vector Z component.', x, y++); + t.print('Tilts camera Z-up orientation.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 50, 150); + t.print(`UP Z: ${upZVal.toFixed(2)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/copy.md b/api/textmode.js/classes/TextmodeCamera/methods/copy.md index 8872aa4b..6657d623 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/copy.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/copy.md @@ -26,5 +26,100 @@ Create a copy of this camera. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let snapshotCam = null; +let useSnapshot = false; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +t.mousePressed(() => { + if (snapshotCam) { + useSnapshot = !useSnapshot; + } +}); + +function drawFortress(tm) { + t.push(); + t.ambientLight(30, 20, 40); + t.pointLight(255, 180, 100, Math.sin(tm) * 16, 14, Math.cos(tm) * 16); + + t.push(); + t.translate(0, 4, 0); + t.char('#'); + t.charColor(240, 180, 100); + t.cellColor(24, 14, 8); + t.box(10, 8, 10); + t.pop(); + + for (let i = 0; i < 4; i++) { + const a = (i * Math.PI) / 2; + t.push(); + t.translate(Math.cos(a) * 7, 7, Math.sin(a) * 7); + t.charColor(100, 220, 255); + t.cellColor(10, 20, 35); + t.char('+'); + t.box(3, 14, 3); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(14, 8, 20); + const tm = t.frameCount * 0.03; + + const liveCam = t + .createCamera() + .setPosition(Math.sin(tm) * 32, 16, Math.cos(tm) * 32) + .lookAt(0, 4, 0); + if (!snapshotCam) snapshotCam = liveCam.copy(); + + const activeCam = useSnapshot ? snapshotCam : liveCam; + t.setCamera(activeCam); + drawFortress(tm); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const modeText = useSnapshot ? 'FREEZE SNAPSHOT (CLONED)' : 'LIVE ORBIT CAMERA'; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.COPY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: DUAL-CAMERA FREEZE-FRAME', x, y++); + t.charColor(140, 160, 190); + t.print('cam.copy() creates an independent', x, y++); + t.print('deep clone of camera transformation.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`MODE: ${modeText}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO TOGGLE VIEWS', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md index d159e860..7b345008 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md @@ -37,5 +37,84 @@ Set camera look-at target. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let bx = 0, + by = 0, + bz = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawBeaconField(bx, by, bz) { + t.push(); + for (let i = -2; i <= 2; i++) { + t.push(); + t.translate(i * 12, 6, -10); + t.charColor(80, 140, 240); + t.cellColor(8, 14, 28); + t.char('#'); + t.box(4, 12, 4); + t.pop(); + } + t.push(); + t.translate(bx, by, bz); + t.charColor(120, 255, 180); + t.cellColor(20, 40, 20); + t.char('@'); + t.box(3, 3, 3); + t.pop(); + t.pop(); +} + +t.draw(() => { + t.background(6, 12, 24); + const tm = t.frameCount * 0.04; + bx = Math.sin(tm) * 18; + by = Math.cos(tm * 0.7) * 8 + 6; + bz = Math.sin(tm * 0.5) * 12; + + const cam = t.createCamera().setPosition(0, 12, 38).lookAt(bx, by, bz); + + t.setCamera(cam); + drawBeaconField(bx, by, bz); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.LOOKAT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: TARGET LOCK TRACKING BEACON', x, y++); + t.charColor(140, 160, 190); + t.print('cam.lookAt(x, y, z) locks camera', x, y++); + t.print('view frustum onto moving target.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TARGET: [${bx.toFixed(1)}, ${by.toFixed(1)}, ${bz.toFixed(1)}]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/move.md b/api/textmode.js/classes/TextmodeCamera/methods/move.md index 0373ea6e..0a93a7fe 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/move.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/move.md @@ -37,5 +37,89 @@ Move eye and target together in world space. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let totalDistance = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawHighway(camZ) { + t.push(); + t.ambientLight(20, 10, 30); + t.pointLight(255, 100, 200, 0, 10, camZ - 15); + + for (let i = 0; i < 16; i++) { + const obeliskZ = Math.floor(camZ / 12) * 12 - i * 12; + t.push(); + t.translate(-14, 4, obeliskZ); + t.charColor(255, 120, 180); + t.cellColor(28, 8, 18); + t.char('#'); + t.box(3, 8, 3); + t.pop(); + + t.push(); + t.translate(14, 4, obeliskZ); + t.charColor(100, 220, 255); + t.cellColor(8, 20, 32); + t.char('#'); + t.box(3, 8, 3); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(14, 4, 18); + + const cam = t + .createCamera() + .setPosition(0, 6, totalDistance) + .lookAt(0, 4, totalDistance - 40); + + cam.move(0, 0, -0.6); + totalDistance = cam.eyeZ; + + t.setCamera(cam); + drawHighway(totalDistance); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.MOVE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: LIT HIGHWAY OBELISK FLYBY', x, y++); + t.charColor(140, 160, 190); + t.print('cam.move(dx, dy, dz) translates eye', x, y++); + t.print('& target together in world space.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL Z DISTANCE: ${totalDistance.toFixed(1)}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md index c23f2a87..f3dfc47f 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md @@ -37,5 +37,83 @@ Set camera eye position. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let curPos = { x: 0, y: 0, z: 0 }; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawMonument(tm, eyeX, eyeY, eyeZ) { + t.push(); + t.ambientLight(60, 80, 120); + t.pointLight(255, 220, 160, eyeX, eyeY + 8, eyeZ); + t.pointLight(100, 200, 255, Math.sin(tm * 2) * 20, 24, Math.cos(tm * 2) * 20); + + for (let ring = 3; ring >= 1; ring--) { + const r = ring * 6; + t.push(); + t.translate(0, (4 - ring) * 3, 0); + t.charColor(100 + ring * 40, 200, 255 - ring * 20); + t.cellColor(12, 22, 38); + t.char('+'); + t.box(r, 2.5, r); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 24); + const tm = t.frameCount * 0.03; + + const eyeX = Math.sin(tm) * 30; + const eyeY = Math.cos(tm * 0.7) * 15 + 10; + const eyeZ = Math.cos(tm) * 30; + + curPos = { x: eyeX, y: eyeY, z: eyeZ }; + + const cam = t.createCamera().setPosition(eyeX, eyeY, eyeZ).lookAt(0, 4, 0); + + t.setCamera(cam); + drawMonument(tm, eyeX, eyeY, eyeZ); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.SETPOSITION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HARMONIC LISSAJOUS ORBIT', x, y++); + t.charColor(140, 160, 190); + t.print('cam.setPosition(x, y, z) explicitly', x, y++); + t.print('sets camera eye world coordinates.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`EYE: [${curPos.x.toFixed(1)}, ${curPos.y.toFixed(1)}, ${curPos.z.toFixed(1)}]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md index 21b30cf5..08bf86d1 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md @@ -37,5 +37,73 @@ Set camera up vector. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let upXVal = 0, + upYVal = 0; + +t.setup(() => { + t.perspective(58, 0.1, 4096); +}); + +function drawSpaceStation() { + t.push(); + t.char('#'); + t.charColor(120, 240, 255); + t.cellColor(10, 24, 40); + t.box(6, 6, 6); + t.char('+'); + t.charColor(255, 200, 100); + t.box(16, 2, 16); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 14); + const tm = t.frameCount * 0.03; + upXVal = Math.cos(tm); + upYVal = Math.sin(tm); + + const cam = t.createCamera().setPosition(0, 0, 32).lookAt(0, 0, 0).setUp(upXVal, upYVal, 0); + + t.setCamera(cam); + drawSpaceStation(); + t.resetCamera(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECAMERA.SETUP', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SPACE STATION STABILIZER', x, y++); + t.charColor(140, 160, 190); + t.print('cam.setUp(x, y, z) defines orientation', x, y++); + t.print('vector for camera up direction.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`UP VECTOR: [${upXVal.toFixed(2)}, ${upYVal.toFixed(2)}, 0.00]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md index a3fb7a8e..0453f633 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md @@ -28,5 +28,74 @@ Number of color attachments available on this framebuffer. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + // Requesting exactly 4 color attachments + fb = t.createFramebuffer({ width: 14, height: 10, attachments: 4 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + fb.begin(); + t.clear(); + t.background(15, 12, 30); + t.charColor(255, 180, 120); + t.char('A'); + t.push(); + t.rotateZ(t.frameCount * 2.0); + t.rect(8, 6); + t.pop(); + fb.end(); + + t.push(); + t.translate(0, 3); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('ATTACHMENTCOUNT', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Number of color attachments.', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const count = fb ? fb.attachmentCount : 0; + drawText(`Attachments: ${count} color targets`, x, y++, 120, 255, 180); + drawText('0: Character/transform data', x, y++, 160, 160, 160); + drawText('1: Primary character color', x, y++, 160, 160, 160); + drawText('2: Secondary background color', x, y++, 160, 160, 160); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md index a6c2f570..8d80f3e5 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md @@ -28,5 +28,73 @@ The underlying WebGLFramebuffer handle. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: 14, height: 14 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + fb.begin(); + t.clear(); + t.background(10, 20, 32); + t.charColor(120, 220, 255); + t.char('F'); + t.push(); + t.rotateZ(t.frameCount * 2.0); + t.rect(8, 8); + t.pop(); + fb.end(); + + t.push(); + t.translate(0, 3); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('FRAMEBUFFER', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('The raw WebGLFramebuffer handle.', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const handleExists = fb && fb.framebuffer !== null; + const typeName = fb && fb.framebuffer ? fb.framebuffer.constructor.name : 'null'; + const handle = handleExists ? 'Active' : 'null'; + drawText(`HANDLE: ${handle}`, x, y++, 120, 255, 180); + drawText(`Type : ${typeName}`, x, y++, 160, 160, 160); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md index 99a91740..2b0c5209 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md @@ -28,5 +28,74 @@ Height of the framebuffer in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: 14, height: 12 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + // Draw vertical ruler ticks inside the framebuffer showing height in cells + fb.begin(); + t.clear(); + t.background(24, 12, 18); + t.charColor(255, 100, 150); + t.char('-'); + t.rect(fb.width, fb.height); + for (let row = 0; row < fb.height; row++) { + const cx = -Math.floor(fb.width / 2); + const cy = -Math.floor(fb.height / 2) + row; + drawText(`${row}`, cx + 1, cy, 255, 220, 140); + } + fb.end(); + + t.push(); + t.translate(0, 3); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('HEIGHT', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Framebuffer height in cells (rows).', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const val = fb ? fb.height : 0; + drawText(`Framebuffer Height: ${val} cells`, x, y++, 120, 255, 180); + drawText(`Canvas : ${t.height} px`, x, y++, 160, 160, 160); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md index 672f284e..2485f680 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md @@ -28,5 +28,78 @@ The color attachment textures owned by this framebuffer. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + // 3-attachment framebuffer: char data, charColor, cellColor + fb = t.createFramebuffer({ width: 14, height: 10, attachments: 3 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + fb.begin(); + t.clear(); + t.background(10, 18, 28); + t.charColor(140, 220, 255); + t.char('T'); + t.push(); + t.rotateZ(t.frameCount * 2.0); + t.rect(8, 6); + t.pop(); + fb.end(); + + t.push(); + t.translate(0, 3); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTURES', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Array of WebGLTexture handles.', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const arr = fb ? fb.textures : []; + drawText(`Count: ${arr.length} textures`, x, y++, 120, 255, 180); + const labels = ['Char/transform', 'charColor', 'cellColor']; + for (let i = 0; i < arr.length; i++) { + const ok = arr[i] instanceof WebGLTexture; + const label = labels[i] ?? 'extra'; + const state = ok ? 'OK' : 'null'; + drawText(`[${i}] ${label}: ${state}`, x, y++, 160, 160, 160); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md index d4ae9dca..ed3dd092 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md @@ -28,5 +28,71 @@ Width of the framebuffer in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: 22, height: 10 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + fb.begin(); + t.clear(); + t.background(12, 24, 18); + + // Border + t.charColor(100, 255, 150); + t.char('|'); + t.rect(fb.width, fb.height); + + fb.end(); + + t.push(); + t.translate(0, 3); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('WIDTH', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Framebuffer width in cells (cols).', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const val = fb ? fb.width : 0; + drawText(`Framebuffer Width: ${val} cells`, x, y++, 120, 255, 180); + drawText(`Canvas : ${t.width} px`, x, y++, 160, 160, 160); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md index 216a1f0c..26a6f12a 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md @@ -29,5 +29,71 @@ and pushes renderer state so drawing commands are isolated from the previous tar ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const fb = t.createFramebuffer({ width: 20, height: 12 }); + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.05; + + fb.begin(); + t.background(15, 10, 30); + for (let i = 0; i < 12; i++) { + const angle = time + i * 0.52; + t.push(); + t.charColor(255, 150 + i * 5, 100 + i * 8); + t.char('@'); + t.translate(Math.cos(angle) * 6, Math.sin(angle) * 4); + t.rect(2, 2); + t.pop(); + } + fb.end(); + + t.background(6, 8, 18); + for (let i = 0; i < 4; i++) { + const angle = time * 0.3 + i * (Math.PI / 2); + t.push(); + t.translate(Math.cos(angle) * 16, Math.sin(angle) * 8); + t.image(fb); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('BEGIN', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Redirect draw calls to the framebuffer.', x, y++, 100, 220, 255); + drawText('4 copies orbit the screen using', x, y++, 140, 160, 190); + drawText('the same offscreen buffer.', x, y++, 140, 160, 190); + drawText('--------------------------------', x, y++, 80, 100, 150); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md index 63b88c74..82216737 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md @@ -28,7 +28,88 @@ Call this when a custom framebuffer is no longer needed to release GPU resources ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb = null; +let fbSize = 12; +let growing = true; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +function rebuildFramebuffer() { + if (fb) fb.dispose(); + + if (growing) { + fbSize += 2; + if (fbSize >= 20) growing = false; + } else { + fbSize -= 2; + if (fbSize <= 10) growing = true; + } + + fb = t.createFramebuffer({ width: fbSize, height: fbSize }); + fb.begin(); + t.background(15, 10, 30); + t.charColor(255, 100, 150); + t.char('+'); + t.rect(fbSize, fbSize); + fb.end(); +} + +t.setup(() => { + rebuildFramebuffer(); +}); + +t.draw(() => { + t.background(8, 10, 18); + + if (t.frameCount % 90 === 0) rebuildFramebuffer(); + + t.push(); + t.translate(0, 2); + t.rotateZ(t.frameCount * 1.5); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('DISPOSE', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Releases GPU resources early.', x, y++, 100, 220, 255); + drawText('Framebuffer is rebuilt every 90 frames.', x, y++, 140, 160, 190); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText(`Size: ${fbSize}x${fbSize} cells`, x, y++, 120, 255, 180); + const rem = 90 - (t.frameCount % 90); + drawText(`Rebuild in: ${rem} frames`, x, y++, 160, 160, 160); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Overrides diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md index 9e3f8cd9..298cf952 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md @@ -29,5 +29,71 @@ and viewport state from the renderer stack. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: 16, height: 10 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + // 1. Begin offscreen render pass + fb.begin(); + t.clear(); + t.background(22, 10, 30); + t.charColor(255, 180, 100); + t.char('O'); + t.rect(fb.width, fb.height); + // 2. end() restores the main canvas as the draw target + fb.end(); + + // 3. Draw the framebuffer result onto the main canvas + t.push(); + t.translate(0, 3); + t.rotateZ(t.frameCount * 1.0); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('END', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Restores main canvas target.', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('1. fb.begin() -> draw to framebuffer', x, y++, 140, 160, 190); + drawText('2. fb.end() -> restore main', x, y++, 140, 160, 190); + drawText('3. t.image(fb)-> blit to screen', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md index f92bd23a..f880afd6 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md @@ -37,5 +37,96 @@ RGBA pixel data for the selected attachment. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: 8, height: 8 }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + fb.begin(); + t.clear(); + t.background(10, 15, 30); + t.push(); + t.rotateZ(t.frameCount * 2.5); + t.charColor(255, 120, 80); + t.char('*'); + t.rect(6, 2); + t.pop(); + fb.end(); + + // Read charColor attachment and render a char-mapped pixel grid + const pixels = fb.readPixels(1); + t.push(); + t.translate(5, -1); + for (let py = 0; py < 8; py++) { + for (let px = 0; px < 8; px++) { + const idx = (py * 8 + px) * 4; + const r = pixels[idx], + g = pixels[idx + 1], + b = pixels[idx + 2]; + t.push(); + t.translate(px, py); + if (r > 30 || g > 30 || b > 30) { + t.charColor(r, g, b); + t.char('#'); + } else { + t.charColor(40, 50, 70); + t.char('.'); + } + t.point(); + t.pop(); + } + } + t.pop(); + + t.push(); + t.translate(-8, 3); + t.image(fb, 16, 16); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('READPIXELS', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Raw RGBA bytes from attachment.', x, y++, 100, 220, 255); + drawText('Right: char-map of pixel data.', x, y++, 140, 160, 190); + drawText('--------------------------------', x, y++, 80, 100, 150); + + const px = fb ? fb.readPixels(1) : []; + drawText(`Buffer: ${px.length} bytes`, x, y++, 120, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md index af0fb701..cdd71790 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md @@ -36,5 +36,80 @@ is resized to match the new dimensions. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let fb; +let currentW = 12; +let currentH = 8; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + fb = t.createFramebuffer({ width: currentW, height: currentH }); +}); + +t.draw(() => { + t.background(8, 10, 18); + + // Oscillate framebuffer dimensions to demonstrate resize() + const nextW = 10 + Math.round((Math.sin(t.frameCount * 0.03) * 0.5 + 0.5) * 16); + const nextH = 6 + Math.round((Math.cos(t.frameCount * 0.04) * 0.5 + 0.5) * 10); + + if (nextW !== currentW || nextH !== currentH) { + fb.resize(nextW, nextH); + currentW = nextW; + currentH = nextH; + } + + fb.begin(); + t.clear(); + t.background(20, 10, 35); + t.charColor(255, 200, 100); + t.char('#'); + t.rect(currentW, currentH); + const sizeStr = `${currentW}x${currentH}`; + drawText(sizeStr, -Math.floor(sizeStr.length / 2), 0, 255, 255, 255); + fb.end(); + + t.push(); + t.translate(0, 3); + t.rotateZ(Math.sin(t.frameCount * 0.02) * 5); + t.image(fb); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('RESIZE', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Resize offscreen textures live.', x, y++, 100, 220, 255); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText(`W: ${currentW} H: ${currentH} cells`, x, y++, 120, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGlyphRamp.md b/api/textmode.js/classes/TextmodeGlyphRamp.md index cd980c3b..4dddda72 100644 --- a/api/textmode.js/classes/TextmodeGlyphRamp.md +++ b/api/textmode.js/classes/TextmodeGlyphRamp.md @@ -23,7 +23,79 @@ Use [Textmodifier.createGlyphRamp](Textmodifier/methods/createGlyphRamp.md) to c ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const ramp = t.createGlyphRamp(' .:-=+*#%@'); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.035; + + const seeds = [ + { x: Math.cos(tm) * (hw * 0.5), y: Math.sin(tm * 0.8) * (hh * 0.5) }, + { x: Math.cos(tm + 2) * (hw * 0.5), y: Math.sin(tm * 1.1 + 2) * (hh * 0.5) }, + { x: Math.cos(tm + 4) * (hw * 0.5), y: Math.sin(tm * 0.9 + 4) * (hh * 0.5) }, + ]; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + let dMin = Infinity; + for (let i = 0; i < seeds.length; i++) { + const d = Math.hypot(x - seeds[i].x, y - seeds[i].y); + if (d < dMin) dMin = d; + } + + const val = Math.min(1, dMin / (hw * 0.65)); + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(40 + val * 200), Math.floor(220 - val * 100), Math.floor(160 + val * 85)); + t.cellColor(Math.floor(6 + val * 15), Math.floor(18 + val * 20), Math.floor(24 + val * 25)); + t.char(ramp.at(val)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGLYPHRAMP.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VORONOI GLYPH RAMP MAPPING', x, y++); + t.charColor(140, 160, 190); + t.print('Creates reusable density ramps.', x, y++); + t.print('Maps Voronoi distances to glyphs.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`RAMP LENGTH: ${ramp.length} GLYPHS`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Constructors @@ -49,7 +121,78 @@ At least two grapheme clusters are required. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const ramp = t.createGlyphRamp(' .:-=+*#%@'); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.035; + + const seeds = [ + { x: Math.cos(tm) * (hw * 0.5), y: Math.sin(tm * 0.8) * (hh * 0.5) }, + { x: Math.cos(tm + 2) * (hw * 0.5), y: Math.sin(tm * 1.1 + 2) * (hh * 0.5) }, + { x: Math.cos(tm + 4) * (hw * 0.5), y: Math.sin(tm * 0.9 + 4) * (hh * 0.5) }, + ]; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + let dMin = Infinity; + for (let i = 0; i < seeds.length; i++) { + const d = Math.hypot(x - seeds[i].x, y - seeds[i].y); + if (d < dMin) dMin = d; + } + + const val = Math.min(1, dMin / (hw * 0.65)); + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(40 + val * 200), Math.floor(220 - val * 100), Math.floor(160 + val * 85)); + t.cellColor(Math.floor(6 + val * 15), Math.floor(18 + val * 20), Math.floor(24 + val * 25)); + t.char(ramp.at(val)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGLYPHRAMP.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VORONOI GLYPH RAMP MAPPING', x, y++); + t.charColor(140, 160, 190); + t.print('Creates reusable density ramps.', x, y++); + t.print('Maps Voronoi distances to glyphs.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`RAMP LENGTH: ${ramp.length} GLYPHS`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` ## Properties @@ -102,7 +245,75 @@ Character from this ramp. ##### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const ramp = t.createGlyphRamp(' .:-=+*#%@'); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(14, 8, 14); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.02; + + const n = 3 + Math.sin(tm * 0.5); + const m = 5 + Math.cos(tm * 0.5); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const nx = (x / (hw || 1)) * Math.PI; + const ny = (y / (hh || 1)) * Math.PI; + const w = Math.cos(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.cos(n * ny); + + const norm = (w + 2) / 4; + t.push(); + t.translate(x, y); + t.charColor(Math.floor(255 - norm * 160), Math.floor(100 + norm * 150), Math.floor(200 - norm * 120)); + t.cellColor(Math.floor(25 - norm * 15), Math.floor(8 + norm * 12), Math.floor(20 + norm * 10)); + t.char(ramp.at(w, -2, 2)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleW = Math.sin(t.frameCount * 0.05) * 2; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGLYPHRAMP.AT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CHLADNI CYMATIC RESONANCE', x, y++); + t.charColor(140, 160, 190); + t.print('at(v, min, max) remaps standing wave', x, y++); + t.print('nodal lines directly to the ramp.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`W: ${sampleW.toFixed(2)} -> GLYPH: "${ramp.at(sampleW, -2, 2)}"`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + #### Call Signature @@ -134,7 +345,75 @@ Character from this ramp. ##### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const ramp = t.createGlyphRamp(' .:-=+*#%@'); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(14, 8, 14); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.02; + + const n = 3 + Math.sin(tm * 0.5); + const m = 5 + Math.cos(tm * 0.5); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const nx = (x / (hw || 1)) * Math.PI; + const ny = (y / (hh || 1)) * Math.PI; + const w = Math.cos(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.cos(n * ny); + + const norm = (w + 2) / 4; + t.push(); + t.translate(x, y); + t.charColor(Math.floor(255 - norm * 160), Math.floor(100 + norm * 150), Math.floor(200 - norm * 120)); + t.cellColor(Math.floor(25 - norm * 15), Math.floor(8 + norm * 12), Math.floor(20 + norm * 10)); + t.char(ramp.at(w, -2, 2)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleW = Math.sin(t.frameCount * 0.05) * 2; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGLYPHRAMP.AT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CHLADNI CYMATIC RESONANCE', x, y++); + t.charColor(140, 160, 190); + t.print('at(v, min, max) remaps standing wave', x, y++); + t.print('nodal lines directly to the ramp.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`W: ${sampleW.toFixed(2)} -> GLYPH: "${ramp.at(sampleW, -2, 2)}"`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + *** @@ -163,5 +442,70 @@ A new shifted ramp. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const baseRamp = t.createGlyphRamp(' .:-=+*#%@'); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const angle = Math.atan2(y, x); + const dist = Math.hypot(x, y); + const shiftAmt = Math.floor((angle / (Math.PI * 2)) * baseRamp.length + tm * 3); + const shiftedRamp = baseRamp.shift(shiftAmt); + const val = (Math.sin(dist * 0.3 - tm * 2) + 1) * 0.5; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(60 + val * 180), Math.floor(200 - val * 80), Math.floor(240 - val * 60)); + t.cellColor(Math.floor(10 + val * 20), Math.floor(25 + val * 25), Math.floor(40 + val * 20)); + t.char(shiftedRamp.at(val)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const shifted = baseRamp.shift(Math.floor(t.frameCount * 0.1)); + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGLYPHRAMP.SHIFT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SHIFTED GLYPH RAMP COPY', x, y++); + t.charColor(140, 160, 190); + t.print('shift(n) returns a rotated copy.', x, y++); + t.print('Original ramp remains unchanged.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SHIFTED: "${shifted.characters}"`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid.md b/api/textmode.js/classes/TextmodeGrid.md index 949906d7..a6e7f155 100644 --- a/api/textmode.js/classes/TextmodeGrid.md +++ b/api/textmode.js/classes/TextmodeGrid.md @@ -23,7 +23,87 @@ You can manually set `cols` and `rows` to lock the grid to a specific size. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 26); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.04; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const isOrigin = x === 0 && y === 0; + const isAxis = x === 0 || y === 0; + const dist = Math.hypot(x, y); + const wave = Math.sin(dist * 0.3 - tm * 2) * 0.5 + 0.5; + + let charKey = '.'; + if (isOrigin) charKey = '@'; + else if (isAxis) charKey = x === 0 ? '|' : '-'; + else charKey = wave > 0.6 ? '+' : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isOrigin ? 255 : isAxis ? 100 : Math.floor(50 + wave * 150), + isOrigin ? 220 : isAxis ? 240 : Math.floor(120 + wave * 100), + isOrigin ? 80 : isAxis ? 255 : Math.floor(180 + wave * 75) + ); + t.cellColor( + isOrigin ? 40 : isAxis ? 14 : Math.floor(6 + wave * 8), + isOrigin ? 28 : isAxis ? 20 : Math.floor(10 + wave * 12), + isOrigin ? 12 : isAxis ? 32 : Math.floor(20 + wave * 14) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const totalCells = t.grid.cols * t.grid.rows; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ARCHITECTURE MATRIX BLUEPRINT', x, y++); + t.charColor(140, 160, 190); + t.print('Grid layout determines character positioning', x, y++); + t.print('and center-based origin coordinates.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`GRID DIMENSIONS: ${t.grid.cols} X ${t.grid.rows}`, x, y++); + t.print(`TOTAL CELL COUNT: ${totalCells} CELLS`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Accessors diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md index 02007593..1c0e35ad 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md @@ -28,5 +28,81 @@ Height of each cell in screen pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.05; + const cH = t.grid.cellHeight; + + for (let y = -hh; y <= hh; y++) { + const isStride = Math.abs(y) % Math.floor(cH / 4 || 1) === 0; + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(x * 0.15 + y * (cH * 0.02) + tm); + const norm = (wave + 1) * 0.5; + + const charKey = isStride ? '=' : norm > 0.6 ? '#' : norm > 0.3 ? '+' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isStride ? 255 : Math.floor(40 + norm * 180), + isStride ? 220 : Math.floor(140 + norm * 110), + isStride ? 100 : Math.floor(240 - norm * 80) + ); + t.cellColor( + isStride ? 24 : Math.floor(6 + norm * 12), + isStride ? 16 : Math.floor(10 + norm * 14), + isStride ? 8 : Math.floor(20 + norm * 18) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const aspect = (t.grid.cellWidth / (t.grid.cellHeight || 1)).toFixed(2); + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.CELLHEIGHT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VERTICAL ASPECT STRIDE SCANNER', x, y++); + t.charColor(140, 160, 190); + t.print('Height of each cell in screen pixels.', x, y++); + t.print('Dictates vertical step stride.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`CELL HEIGHT: ${t.grid.cellHeight} PX`, x, y++); + t.print(`CELL ASPECT: ${aspect}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md index b9f7e64b..9f60b095 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md @@ -28,5 +28,78 @@ Width of each cell in screen pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(8, 14, 24); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.05; + const cW = t.grid.cellWidth; + + for (let x = -hw; x <= hw; x++) { + const isStride = Math.abs(x) % Math.floor(cW / 3 || 1) === 0; + for (let y = -hh; y <= hh; y++) { + const wave = Math.cos(y * 0.15 + x * (cW * 0.03) + tm); + const norm = (wave + 1) * 0.5; + + const charKey = isStride ? '|' : norm > 0.6 ? '*' : norm > 0.3 ? ':' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isStride ? 100 : Math.floor(60 + norm * 180), + isStride ? 240 : Math.floor(180 + norm * 70), + isStride ? 255 : Math.floor(120 + norm * 130) + ); + t.cellColor( + isStride ? 8 : Math.floor(8 + norm * 10), + isStride ? 24 : Math.floor(12 + norm * 16), + isStride ? 32 : Math.floor(22 + norm * 14) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.CELLWIDTH', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HORIZONTAL COLUMN STRIDE MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('Width of each cell in screen pixels.', x, y++); + t.print('Dictates column horizontal density.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`CELL WIDTH: ${t.grid.cellWidth} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md index bdf9e22f..ce134e3a 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md @@ -28,7 +28,82 @@ Number of columns in the grid. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 22); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.04; + + for (let c = 0; c < cols; c++) { + const x = c - hw; + const wave = Math.sin(c * 0.3 + tm) * 0.5 + Math.cos(c * 0.12 - tm * 1.5) * 0.3 + 0.5; + const barH = Math.floor(1 + wave * (rows - 4)); + const ramp = ['.', ':', '+', '*', '#', '%', '@']; + + for (let r = 0; r < barH; r++) { + const y = hh - r; + const ci = Math.min(ramp.length - 1, Math.floor((r / Math.max(1, barH - 1)) * ramp.length)); + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(60 + wave * 140), Math.floor(140 + ci * 15), Math.floor(255 - ci * 10)); + t.cellColor(Math.floor(8 + ci * 3), Math.floor(16 + ci * 4), Math.floor(30 + ci * 5)); + t.char(ramp[ci]); + t.point(); + t.pop(); + } + + t.push(); + t.translate(x, hh - barH); + t.charColor(255, 220, 100); + t.cellColor(40, 30, 10); + t.char('*'); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.COLS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: MULTI-CHANNEL EQUALIZER SPECTRUM', x, y++); + t.charColor(140, 160, 190); + t.print('Number of columns in grid layout.', x, y++); + t.print('Renders exact 1:1 column frequency bars.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL COLUMNS: ${t.grid.cols}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Set Signature @@ -50,5 +125,81 @@ Set the number of columns and lock grid sizing until `responsive()` is called. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const presets = [16, 32, 48, 64]; +let presetIdx = 1; + +t.setup(() => { + t.grid.cols = presets[presetIdx]; +}); + +t.mousePressed(() => { + presetIdx = (presetIdx + 1) % presets.length; + t.grid.cols = presets[presetIdx]; +}); + +t.draw(() => { + t.background(6, 14, 22); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.05; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 + tm); + const norm = (wave + 1) * 0.5; + + const charKey = norm > 0.7 ? '#' : norm > 0.4 ? '+' : norm > 0.2 ? ':' : '.'; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(80 + norm * 175), Math.floor(200 + norm * 55), Math.floor(140 - norm * 60)); + t.cellColor(Math.floor(6 + norm * 10), Math.floor(18 + norm * 14), Math.floor(12 + norm * 16)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.SETCOLS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: COLUMN DENSITY QUANTIZER', x, y++); + t.charColor(140, 160, 190); + t.print('Sets column count and locks grid size', x, y++); + t.print('until responsive() is called.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`LOCKED COLS: ${t.grid.cols}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO CYCLE COLS PRESETS', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/height.md b/api/textmode.js/classes/TextmodeGrid/accessors/height.md index 79792e1d..13935713 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/height.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/height.md @@ -30,5 +30,85 @@ This is equal to `rows * cellHeight`. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 22); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let y = top; y <= bottom; y++) { + const normY = (y - top) / Math.max(1, rows - 1); + const pulse = Math.sin(normY * Math.PI * 4 - tm * 2) * 0.5 + 0.5; + + for (let x = left; x <= right; x++) { + const isBorder = x === left || x === right || y === top || y === bottom; + const isRuler = x === left + 1 || x === right - 1; + + let charKey = '.'; + if (isBorder) charKey = '#'; + else if (isRuler) charKey = (y - top) % 5 === 0 ? '+' : '|'; + else charKey = pulse > 0.6 ? '*' : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isBorder ? 255 : isRuler ? 120 : Math.floor(40 + pulse * 140), + isBorder ? 180 : isRuler ? 240 : Math.floor(100 + pulse * 100), + isBorder ? 80 : isRuler ? 200 : Math.floor(180 + pulse * 75) + ); + t.cellColor( + isBorder ? 24 : Math.floor(6 + pulse * 10), + isBorder ? 16 : Math.floor(10 + pulse * 12), + isBorder ? 8 : Math.floor(20 + pulse * 16) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.HEIGHT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VERTICAL VIEWPORT BOUNDS RULER', x, y++); + t.charColor(140, 160, 190); + t.print('Total grid height in screen pixels.', x, y++); + t.print('Equal to rows * cellHeight.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL HEIGHT: ${t.grid.height} PX`, x, y++); + t.print(`CALC: ${t.grid.rows} * ${t.grid.cellHeight} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md index 0ee303d7..71245d36 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md @@ -28,5 +28,77 @@ Horizontal offset in pixels from the canvas edge to the grid. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.04; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const isBorder = x === left || x === right || y === top || y === bottom; + const isCenter = x === 0 || y === 0; + + let charKey = '.'; + if (isBorder) charKey = '#'; + else if (isCenter) charKey = '+'; + else charKey = Math.sin(x * 0.2 + y * 0.2 + tm) > 0 ? '=' : '-'; + + t.push(); + t.translate(x, y); + t.charColor( + isBorder ? 255 : isCenter ? 120 : 80, + isBorder ? 200 : isCenter ? 240 : 160, + isBorder ? 100 : isCenter ? 180 : 240 + ); + t.cellColor(isBorder ? 30 : 10, isBorder ? 20 : 14, isBorder ? 10 : 28); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.OFFSETX', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CANVAS CENTERING ALIGNMENT', x, y++); + t.charColor(140, 160, 190); + t.print('Horizontal offset in pixels from canvas', x, y++); + t.print('edge to grid to center grid content.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`OFFSET X: ${t.grid.offsetX} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md index b5d8115d..c17ac881 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md @@ -28,5 +28,77 @@ Vertical offset in pixels from the canvas edge to the grid. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 4, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.04; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const isBorder = x === left || x === right || y === top || y === bottom; + const isCenter = x === 0 || y === 0; + + let charKey = '.'; + if (isBorder) charKey = '#'; + else if (isCenter) charKey = '+'; + else charKey = Math.cos(x * 0.2 + y * 0.2 + tm) > 0 ? '|' : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isBorder ? 255 : isCenter ? 240 : 100, + isBorder ? 180 : isCenter ? 120 : 140, + isBorder ? 120 : isCenter ? 255 : 240 + ); + t.cellColor(isBorder ? 28 : 12, isBorder ? 14 : 8, isBorder ? 12 : 30); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.OFFSETY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VERTICAL CENTERING ALIGNMENT', x, y++); + t.charColor(140, 160, 190); + t.print('Vertical offset in pixels from canvas', x, y++); + t.print('edge to grid to center grid content.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`OFFSET Y: ${t.grid.offsetY} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md index df335515..810b48b2 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md @@ -28,7 +28,82 @@ Number of rows in the grid. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(18, 8, 6); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.04; + + for (let r = 0; r < rows; r++) { + const y = r - hh; + const wave = Math.sin(r * 0.25 + tm) * 0.5 + Math.cos(r * 0.1 - tm * 1.3) * 0.3 + 0.5; + const bandLen = Math.floor(2 + wave * (cols - 4)); + const ramp = ['.', ':', '+', '*', '#', '%', '@']; + + for (let c = 0; c < bandLen; c++) { + const x = c - hw; + const ci = Math.min(ramp.length - 1, Math.floor((c / Math.max(1, bandLen - 1)) * ramp.length)); + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(255 - ci * 15), Math.floor(120 + wave * 100), Math.floor(60 + ci * 20)); + t.cellColor(Math.floor(32 + ci * 4), Math.floor(14 + ci * 2), Math.floor(8 + ci)); + t.char(ramp[ci]); + t.point(); + t.pop(); + } + + t.push(); + t.translate(bandLen - hw, y); + t.charColor(255, 200, 100); + t.cellColor(40, 20, 8); + t.char('*'); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.ROWS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HORIZONTAL STRATIGRAPHY STRATA', x, y++); + t.charColor(140, 160, 190); + t.print('Number of rows in grid layout.', x, y++); + t.print('Renders exact 1:1 row terrain bands.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL ROWS: ${t.grid.rows}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Set Signature @@ -50,5 +125,81 @@ Set the number of rows and lock grid sizing until `responsive()` is called. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const presets = [12, 24, 36, 48]; +let presetIdx = 1; + +t.setup(() => { + t.grid.rows = presets[presetIdx]; +}); + +t.mousePressed(() => { + presetIdx = (presetIdx + 1) % presets.length; + t.grid.rows = presets[presetIdx]; +}); + +t.draw(() => { + t.background(14, 8, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.05; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.cos(x * 0.2 - tm) * Math.sin(y * 0.2 + tm); + const norm = (wave + 1) * 0.5; + + const charKey = norm > 0.7 ? '%' : norm > 0.4 ? '*' : norm > 0.2 ? '=' : '-'; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(220 + norm * 35), Math.floor(120 + norm * 100), Math.floor(80 + norm * 120)); + t.cellColor(Math.floor(20 + norm * 12), Math.floor(8 + norm * 10), Math.floor(14 + norm * 16)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.SETROWS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ROW DENSITY QUANTIZER', x, y++); + t.charColor(140, 160, 190); + t.print('Sets row count and locks grid size', x, y++); + t.print('until responsive() is called.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`LOCKED ROWS: ${t.grid.rows}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO CYCLE ROWS PRESETS', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/width.md b/api/textmode.js/classes/TextmodeGrid/accessors/width.md index 55320abf..203fffc6 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/width.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/width.md @@ -30,5 +30,85 @@ This is equal to `cols * cellWidth`. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(10, 14, 24); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let x = left; x <= right; x++) { + const normX = (x - left) / Math.max(1, cols - 1); + const pulse = Math.cos(normX * Math.PI * 4 - tm * 2) * 0.5 + 0.5; + + for (let y = top; y <= bottom; y++) { + const isBorder = x === left || x === right || y === top || y === bottom; + const isRuler = y === top + 1 || y === bottom - 1; + + let charKey = '.'; + if (isBorder) charKey = '#'; + else if (isRuler) charKey = (x - left) % 5 === 0 ? '+' : '-'; + else charKey = pulse > 0.6 ? '*' : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isBorder ? 255 : isRuler ? 100 : Math.floor(60 + pulse * 140), + isBorder ? 200 : isRuler ? 220 : Math.floor(140 + pulse * 100), + isBorder ? 100 : isRuler ? 255 : Math.floor(120 + pulse * 80) + ); + t.cellColor( + isBorder ? 24 : Math.floor(8 + pulse * 10), + isBorder ? 18 : Math.floor(14 + pulse * 12), + isBorder ? 10 : Math.floor(24 + pulse * 14) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.WIDTH', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HORIZONTAL VIEWPORT BOUNDS RULER', x, y++); + t.charColor(140, 160, 190); + t.print('Total grid width in screen pixels.', x, y++); + t.print('Equal to cols * cellWidth.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL WIDTH: ${t.grid.width} PX`, x, y++); + t.print(`CALC: ${t.grid.cols} * ${t.grid.cellWidth} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/methods/reset.md b/api/textmode.js/classes/TextmodeGrid/methods/reset.md index 669521dc..80ccd8b8 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/reset.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/reset.md @@ -32,5 +32,87 @@ You typically do not need to call this method directly. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let resetPulse = 0; + +t.setup(() => {}); + +t.mousePressed(() => { + t.grid.reset(); + resetPulse = 1.0; +}); + +t.draw(() => { + t.background(6, 12, 24); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + if (resetPulse > 0) resetPulse -= 0.03; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const wave = Math.sin(dist * 0.4 - tm * 3 + resetPulse * 6); + const norm = (wave + 1) * 0.5; + + const charKey = resetPulse > 0.5 ? '#' : norm > 0.6 ? '+' : norm > 0.3 ? ':' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + resetPulse > 0 ? 255 : Math.floor(60 + norm * 180), + resetPulse > 0 ? Math.floor(180 + resetPulse * 75) : Math.floor(140 + norm * 110), + resetPulse > 0 ? Math.floor(100 + resetPulse * 155) : Math.floor(220 - norm * 80) + ); + t.cellColor(Math.floor(8 + norm * 12), Math.floor(12 + norm * 14), Math.floor(24 + norm * 16)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.RESET', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: INTERACTIVE GRID RECALCULATION', x, y++); + t.charColor(140, 160, 190); + t.print('Recalculates columns and rows from', x, y++); + t.print('current canvas & cell dimensions.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`GRID: ${t.grid.cols} X ${t.grid.rows}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO TRIGGER RESET()', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md index b79a3e39..718ecc67 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md @@ -28,5 +28,90 @@ A grid becomes non-responsive when either `cols` or `rows` is manually set. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let isManual = false; + +t.setup(() => {}); + +t.mousePressed(() => { + isManual = !isManual; + if (isManual) { + t.grid.cols = 32; + t.grid.rows = 16; + } else { + t.grid.responsive(); + t.grid.reset(); + } +}); + +t.draw(() => { + t.background(8, 12, 26); + const cols = t.grid.cols; + const rows = t.grid.rows; + const hw = Math.floor(cols / 2); + const hh = Math.floor(rows / 2); + const tm = t.frameCount * 0.04; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 - tm); + const norm = (wave + 1) * 0.5; + + const charKey = isManual ? (norm > 0.5 ? '#' : '=') : norm > 0.6 ? '*' : norm > 0.3 ? '+' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isManual ? 255 : Math.floor(80 + norm * 160), + isManual ? Math.floor(140 + norm * 100) : Math.floor(200 + norm * 55), + isManual ? 100 : Math.floor(140 - norm * 60) + ); + t.cellColor(isManual ? 24 : 8, isManual ? 12 : 16, isManual ? 8 : 28); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const modeText = isManual ? 'MANUAL LOCKED (32x16)' : 'AUTO RESPONSIVE'; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEGRID.RESPONSIVE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: RESPONSIVE AUTO-SIZING TOGGLE', x, y++); + t.charColor(140, 160, 190); + t.print('Restores responsive sizing so resizes', x, y++); + t.print('recalculate columns and rows.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`GRID SIZING: ${modeText}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO TOGGLE RESPONSIVE', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeShader.md b/api/textmode.js/classes/TextmodeShader.md index 62a24fd8..6c5afd97 100644 --- a/api/textmode.js/classes/TextmodeShader.md +++ b/api/textmode.js/classes/TextmodeShader.md @@ -44,7 +44,79 @@ Get the WebGL program ##### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let customShader = null; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + customShader = await t.createMaterialShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + vec2 centered = v_uv - 0.5; + float rings = sin(length(centered) * 42.0 - u_time * 3.0); + float scan = sin((v_uv.x + v_uv.y) * 26.0 + u_time * 2.0); + float glyph = step(0.0, rings + scan * 0.45); + o_character = vec4(glyph, 0.0, 0.0, 1.0); + o_primaryColor = vec4(0.28 + glyph * 0.6, 0.82, 1.0, 1.0); + o_secondaryColor = vec4(0.02, 0.04, 0.09, 1.0); +}`); +}); + +t.draw(() => { + t.background(4, 7, 18); + + if (!customShader) return; + + t.shader(customShader); + t.setUniform('u_time', t.frameCount * 0.025); + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESHADER.PROGRAM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: WEBGL PROGRAM HANDLE', x, y++, 100, 220, 255); + drawText('Filter shader draws the grid.', x, y++, 140, 160, 190); + drawText('program exposes the raw handle.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + const ready = customShader && customShader.program instanceof WebGLProgram; + const state = ready ? 'READY' : 'WAIT'; + drawText(`PROGRAM: ${state}`, x, y++, 140, 255, 180); + drawText('TYPE: WEBGLPROGRAM', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Methods @@ -62,7 +134,103 @@ Dispose of WebGL resources used by this shader. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let customShader = null; +let isDisposed = false; + +function drawText(text, x, y, r = 200, g = 220, b = 255) { + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +async function createShader() { + const vert = `#version 300 es + in vec4 a_position; in vec2 a_uv; out vec2 v_uv; + void main() { gl_Position = a_position; v_uv = a_uv; }`; + const frag = `#version 300 es + precision highp float; in vec2 v_uv; + layout(location = 0) out vec4 o_char; + layout(location = 1) out vec4 o_fg; + layout(location = 2) out vec4 o_bg; + void main() { + float s = step(0.5, fract((v_uv.x + v_uv.y) * 10.0)); + o_char = vec4(s, 0.0, 0.0, 0.0); + o_fg = vec4(1.0, 0.75 - s * 0.3, 0.25 + s * 0.4, 1.0); + o_bg = vec4(0.03, 0.05, 0.1, 1.0); + }`; + customShader = await t.createShader(vert, frag); + isDisposed = false; +} + +t.setup(async () => { + await createShader(); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (customShader && !isDisposed) { + t.push(); + t.shader(customShader); + t.charColor(255, 180, 100); + t.rect(14, 6); + t.resetShader(); + t.pop(); + } else { + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(14, 6); + t.pop(); + } +}); + +t.mouseClicked(async () => { + if (customShader && !isDisposed) { + customShader.dispose(); + isDisposed = true; + } else { + await createShader(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('DISPOSE', x, y++, 100, 255, 140); + drawText('--------------------------------', x, y++, 80, 100, 150); + drawText('Frees the GL program handle.', x, y++, 100, 220, 255); + drawText('Click to dispose / rebuild.', x, y++, 140, 160, 190); + drawText('--------------------------------', x, y++, 80, 100, 150); + const status = isDisposed ? 'OFFLINE' : 'ACTIVE'; + const sr = isDisposed ? 255 : 140; + const sg = isDisposed ? 100 : 255; + drawText(`GPU STATUS: ${status}`, x, y++, sr, sg, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + #### Overrides diff --git a/api/textmode.js/classes/TextmodeVector.md b/api/textmode.js/classes/TextmodeVector.md index b4e3fedb..1460ac9a 100644 --- a/api/textmode.js/classes/TextmodeVector.md +++ b/api/textmode.js/classes/TextmodeVector.md @@ -23,7 +23,100 @@ Use [Textmodifier.createVector](Textmodifier/methods/createVector.md) to create ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Constructors diff --git a/api/textmode.js/classes/TextmodeVector/methods/add.md b/api/textmode.js/classes/TextmodeVector/methods/add.md index a5ff479a..4c4dc76a 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/add.md +++ b/api/textmode.js/classes/TextmodeVector/methods/add.md @@ -38,7 +38,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -67,5 +160,97 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/copy.md b/api/textmode.js/classes/TextmodeVector/methods/copy.md index c201a51c..eb7efbad 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/copy.md +++ b/api/textmode.js/classes/TextmodeVector/methods/copy.md @@ -28,5 +28,97 @@ A new vector with the same components. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/cross.md b/api/textmode.js/classes/TextmodeVector/methods/cross.md index 5571f8f2..dc470d6f 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/cross.md +++ b/api/textmode.js/classes/TextmodeVector/methods/cross.md @@ -36,7 +36,100 @@ A new vector containing the cross product. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -65,5 +158,97 @@ A new vector containing the cross product. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/dist.md b/api/textmode.js/classes/TextmodeVector/methods/dist.md index cda731eb..7ad2576d 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dist.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dist.md @@ -36,7 +36,100 @@ Euclidean distance between the two points. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -65,5 +158,97 @@ Euclidean distance between the two points. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/div.md b/api/textmode.js/classes/TextmodeVector/methods/div.md index f70a0188..0c534c07 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/div.md +++ b/api/textmode.js/classes/TextmodeVector/methods/div.md @@ -36,7 +36,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -62,7 +155,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -91,5 +277,97 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/dot.md b/api/textmode.js/classes/TextmodeVector/methods/dot.md index 199ae927..55f27fd4 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dot.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dot.md @@ -36,7 +36,100 @@ Dot product. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -65,5 +158,97 @@ Dot product. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/heading.md b/api/textmode.js/classes/TextmodeVector/methods/heading.md index bd43c21a..ce9f52d5 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/heading.md +++ b/api/textmode.js/classes/TextmodeVector/methods/heading.md @@ -31,5 +31,97 @@ Heading angle in degrees. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/limit.md b/api/textmode.js/classes/TextmodeVector/methods/limit.md index 4c3acbec..c0c42e02 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/limit.md +++ b/api/textmode.js/classes/TextmodeVector/methods/limit.md @@ -34,5 +34,97 @@ This vector. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/mag.md b/api/textmode.js/classes/TextmodeVector/methods/mag.md index 625ece54..48ab4b32 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mag.md @@ -28,5 +28,97 @@ The vector length. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/magSq.md b/api/textmode.js/classes/TextmodeVector/methods/magSq.md index 05b3c0f9..7bd58c22 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/magSq.md +++ b/api/textmode.js/classes/TextmodeVector/methods/magSq.md @@ -30,5 +30,97 @@ The squared vector length. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/mult.md b/api/textmode.js/classes/TextmodeVector/methods/mult.md index 1fb83d89..eed1b0a1 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mult.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mult.md @@ -36,7 +36,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -62,7 +155,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -91,5 +277,97 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/normalize.md b/api/textmode.js/classes/TextmodeVector/methods/normalize.md index 8142a039..abdbbba0 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/normalize.md +++ b/api/textmode.js/classes/TextmodeVector/methods/normalize.md @@ -30,5 +30,97 @@ This vector. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/set.md b/api/textmode.js/classes/TextmodeVector/methods/set.md index 3cad3dfa..f09872f1 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/set.md +++ b/api/textmode.js/classes/TextmodeVector/methods/set.md @@ -39,7 +39,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -68,5 +161,97 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/setMag.md b/api/textmode.js/classes/TextmodeVector/methods/setMag.md index da7e3ff5..5cd6cd7f 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/setMag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/setMag.md @@ -36,5 +36,97 @@ This vector. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/sub.md b/api/textmode.js/classes/TextmodeVector/methods/sub.md index 46849413..ff32cfb2 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/sub.md +++ b/api/textmode.js/classes/TextmodeVector/methods/sub.md @@ -38,7 +38,100 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -67,5 +160,97 @@ This vector. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/canvas.md b/api/textmode.js/classes/Textmodifier/accessors/canvas.md index 87d7817e..0370cfdd 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/canvas.md +++ b/api/textmode.js/classes/Textmodifier/accessors/canvas.md @@ -28,5 +28,83 @@ Canvas containing the rendered output. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); + +t.canvas.title = 'Textmodifier.canvas'; +t.canvas.dataset.example = 'canvas'; +t.canvas.style.background = '#060713'; +t.canvas.style.outlineOffset = '-4px'; + +function updateCanvasElement() { + const hue = Math.floor((t.frameCount * 2) % 360); + t.canvas.style.outline = `3px solid hsl(${hue}, 90%, 62%)`; + t.canvas.style.boxShadow = `0 0 24px hsla(${hue}, 90%, 62%, 0.28)`; +} + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + updateCanvasElement(); + t.background(6, 8, 20); + + const cols = Math.floor(t.grid.cols / 2); + const rows = Math.floor(t.grid.rows / 2); + t.charColor(255, 190, 80); + for (let x = -cols; x <= cols; x += 4) { + t.push(); + t.translate(x, -rows + 1); + t.char('='); + t.point(); + t.translate(0, rows * 2 - 2); + t.point(); + t.pop(); + } + for (let y = -rows + 1; y < rows; y += 2) { + t.push(); + t.translate(-cols + 1, y); + t.char('|'); + t.point(); + t.translate(cols * 2 - 2, 0); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const size = `${t.canvas.width}x${t.canvas.height}`; + const title = t.canvas.title; + + drawText('TEXTMODIFIER.CANVAS', x, y++, 255, 190, 80); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DOM CANVAS ACCESS', x, y++, 100, 220, 255); + drawText('The getter returns the element.', x, y++, 140, 160, 190); + drawText('CSS and metadata update live.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SIZE: ${size}`, x, y++, 140, 190, 255); + drawText(`TITLE: ${title}`, x, y++, 150, 240, 170); + drawText('DATASET: canvas', x, y++, 150, 240, 170); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/conversions.md b/api/textmode.js/classes/Textmodifier/accessors/conversions.md index ea2c26a0..dbed9007 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/conversions.md +++ b/api/textmode.js/classes/Textmodifier/accessors/conversions.md @@ -31,5 +31,50 @@ when converting images/videos/canvases into textmode representations. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let hasBrightness = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + hasBrightness = t.conversions.has('brightness'); + t.char(hasBrightness ? '@' : '.'); + t.charColor(140, 220, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: IMAGE MAPPING', x, y++, 100, 220, 255); + drawText('Conversion registry maps sources.', x, y++, 140, 160, 190); + drawText('Built-ins can be queried.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(hasBrightness ? 'BRIGHTNESS: YES' : 'BRIGHTNESS: NO', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/errors.md b/api/textmode.js/classes/Textmodifier/accessors/errors.md index e53a6bfb..17065ec7 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/errors.md +++ b/api/textmode.js/classes/Textmodifier/accessors/errors.md @@ -28,5 +28,72 @@ Built-in fatal error layer controller. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +let triggerError = false; +const labelLayer = t.layers.add(); + +window.addEventListener( + 'click', + () => { + triggerError = true; + }, + { once: true } +); + +t.draw(() => { + t.background(10, 12, 24); + + // Render a spinning neon cyan gear to demonstrate active draw loop + const time = t.frameCount * 0.05; + for (let i = 0; i < 8; i++) { + const angle = time + (i / 8) * Math.PI * 2; + t.push(); + t.translate(Math.cos(angle) * 8, Math.sin(angle) * 4); + t.charColor(0, 180, 255); + t.char('*'); + t.point(); + t.pop(); + } + + if (triggerError) { + throw new Error('This example intentionally triggers the error layer.'); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.ERRORS', x, y++, 255, 100, 100); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: AUTOMATED RUNTIME ERROR CAPTURE', x, y++, 100, 220, 255); + drawText('Shows fallback error overlay.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = Boolean(t.errors) ? 'TRUE' : 'FALSE'; + drawText(`ERRORS: ${state}`, x, y++, 140, 190, 255); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CLICK TO TRIGGER ERROR', x, y++, 255, 200, 100); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/filters.md b/api/textmode.js/classes/Textmodifier/accessors/filters.md index 522085b3..d4f2baf8 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/filters.md +++ b/api/textmode.js/classes/Textmodifier/accessors/filters.md @@ -50,5 +50,50 @@ t.draw(() => { }); ``` - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let count = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + count = ['invert', 'grayscale', 'sepia'].filter((name) => t.filters.has(name)).length; + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILTERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FILTER REGISTRY', x, y++, 100, 220, 255); + drawText('Queries available filters.', x, y++, 140, 160, 190); + drawText('Registry is shared by output.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`BUILTINS: ${count}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/font.md b/api/textmode.js/classes/Textmodifier/accessors/font.md index 24542d3e..fe355223 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/font.md +++ b/api/textmode.js/classes/Textmodifier/accessors/font.md @@ -31,5 +31,52 @@ Font or tileset used by the current drawing layer. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let index = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const chars = t.font.characters; + index = Math.floor(t.frameCount / 6) % chars.length; + t.char(chars[index].character); + t.charColor(255, 210, 120); + t.rect(8, 4); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FONT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACTIVE FONT', x, y++, 100, 220, 255); + drawText('Reads glyph metadata.', x, y++, 140, 160, 190); + drawText('Current glyph cycles.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`GLYPHS: ${t.font.characters.length}`, x, y++, 140, 255, 180); + drawText(`INDEX: ${index}`, x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md index 555a899b..0a2fe2b0 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md +++ b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md @@ -35,7 +35,54 @@ Number of frames rendered since the sketch started. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.push(); + t.translate(8, 2); + t.rotateZ(t.frameCount * 2); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 2); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FRAMECOUNT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FRAME COUNTER', x, y++, 100, 220, 255); + drawText('Counter increments each frame.', x, y++, 140, 160, 190); + drawText('Rotation uses frameCount.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FRAME: ${t.frameCount}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Set Signature @@ -60,5 +107,55 @@ point in time-based patterns. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.keyPressed((data) => { + if (data.key === ' ') t.frameCount = 0; +}); + +t.draw(() => { + t.background(6, 10, 22); + const phase = (t.frameCount % 120) / 120; + t.push(); + t.translate(-16 + phase * 32, 2); + t.char('@'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FRAMECOUNT2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESET COUNTER', x, y++, 100, 220, 255); + drawText('Space rewinds animation.', x, y++, 140, 160, 190); + drawText('frameCount is writable.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FRAME: ${t.frameCount}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/grid.md b/api/textmode.js/classes/Textmodifier/accessors/grid.md index f2e51333..8f7133f6 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/grid.md +++ b/api/textmode.js/classes/Textmodifier/accessors/grid.md @@ -32,5 +32,49 @@ If no grid is set (e.g., before user setup()), returns `undefined`. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.charColor(50, 70, 100); + t.char('.'); + for (let x = -20; x <= 20; x += 4) t.line(x, -10, x, 10); + for (let y = -10; y <= 10; y += 2) t.line(-20, y, 20, y); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.GRID', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GRID METRICS', x, y++, 100, 220, 255); + drawText('Exposes rows, cols, and cells.', x, y++, 140, 160, 190); + drawText('Grid changes with window size.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`COLS: ${t.grid.cols}`, x, y++, 140, 255, 180); + drawText(`ROWS: ${t.grid.rows}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/height.md b/api/textmode.js/classes/Textmodifier/accessors/height.md index d21c95ea..327fd9c6 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/height.md +++ b/api/textmode.js/classes/Textmodifier/accessors/height.md @@ -28,5 +28,47 @@ Canvas height in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.char('|'); + t.charColor(140, 220, 255); + t.rect(1, t.grid.rows); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.HEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CANVAS HEIGHT', x, y++, 100, 220, 255); + drawText('Returns pixel height.', x, y++, 140, 160, 190); + drawText('Line spans grid rows.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`HEIGHT: ${t.height}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md index 3220b3fb..c8a37b52 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md @@ -28,5 +28,51 @@ Whether this instance has been destroyed. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (!t.isDisposed) t.destroy(); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char(t.isDisposed ? 'X' : '#'); + t.charColor(t.isDisposed ? 255 : 140, t.isDisposed ? 120 : 220, 180); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ISDISPOSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISPOSED FLAG', x, y++, 100, 220, 255); + drawText('Click calls destroy().', x, y++, 140, 160, 190); + drawText('Flag reports lifecycle state.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(t.isDisposed ? 'DISPOSED: YES' : 'DISPOSED: NO', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md index ca385eac..59deb91d 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md @@ -28,5 +28,55 @@ Check if rendering is currently in progress for this frame. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let outsideFrame = false; +setInterval(() => { + outsideFrame = t.isRenderingFrame; +}, 120); + +t.draw(() => { + t.background(6, 10, 22); + t.char(t.isRenderingFrame ? '1' : '0'); + t.charColor(120, 220, 255); + t.rect(12, 8); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.ISRENDERINGFRAME', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FRAME GUARD FLAG', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const inside = t.isRenderingFrame ? 'TRUE' : 'FALSE'; + const outside = outsideFrame ? 'TRUE' : 'FALSE'; + drawText(`INSIDE: ${inside}`, x, y++, 140, 255, 180); + drawText(`OUTSIDE: ${outside}`, x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/layers.md b/api/textmode.js/classes/Textmodifier/accessors/layers.md index f0d7e0f4..1d2ecd8a 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/layers.md +++ b/api/textmode.js/classes/Textmodifier/accessors/layers.md @@ -31,5 +31,57 @@ Each layer has its own grid, font, draw callback, and filters. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const topLayer = t.layers.add({ blendMode: 'additive' }); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +topLayer.draw(() => { + t.clear(); + t.char('+'); + t.charColor(255, 210, 120); + t.rect(8, 4); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 5); + topLayer.offset(Math.sin(t.frameCount * 0.03) * 30, 0); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LAYERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LAYER MANAGER', x, y++, 100, 220, 255); + drawText('Accesses the layer stack.', x, y++, 140, 160, 190); + drawText('Overlay layer moves in pixels.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`LAYERS: ${t.layers.all.length}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/loading.md b/api/textmode.js/classes/Textmodifier/accessors/loading.md index 6d89cb03..6bbd6304 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/loading.md +++ b/api/textmode.js/classes/Textmodifier/accessors/loading.md @@ -28,5 +28,59 @@ Built-in loading layer controller. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + loadingScreen: { transitionDuration: 300 }, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + t.loading.draw((ctx) => { + const tm = ctx.textmodifier; + tm.background(8, 10, 18); + tm.char('#'); + tm.charColor(100, 220, 255); + tm.rect(16, 4); + }); + await new Promise((resolve) => setTimeout(resolve, 400)); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char('@'); + t.charColor(140, 255, 180); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOADING', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOADING SCREEN', x, y++, 100, 220, 255); + drawText('Custom loading draw callback.', x, y++, 140, 160, 190); + drawText('Setup waits briefly.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STATUS: READY', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/millis.md b/api/textmode.js/classes/Textmodifier/accessors/millis.md index e9b50702..ecfad57c 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/millis.md +++ b/api/textmode.js/classes/Textmodifier/accessors/millis.md @@ -39,11 +39,164 @@ Milliseconds since the sketch started. ### Examples - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); - +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = t.millis / 1000; + const angle = (value % 6.28) * 1; + t.push(); + t.translate(8, 2); + t.rotateZ((angle * 180) / Math.PI); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MILLIS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ELAPSED TIME', x, y++, 100, 220, 255); + drawText('Numeric time drives motion.', x, y++, 140, 160, 190); + drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = (t.millis % 2000) / 1000; + const angle = (value % 6.28) * 1; + t.push(); + t.translate(8, 2); + t.rotateZ((angle * 180) / Math.PI); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MILLIS2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MODULO TIMER', x, y++, 100, 220, 255); + drawText('Numeric time drives motion.', x, y++, 140, 160, 190); + drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.keyPressed((data) => { + if (data.key === ' ') t.millis = 0; +}); + +t.draw(() => { + t.background(6, 10, 22); + const progress = (t.millis % 3000) / 3000; + for (let i = 0; i < 24; i++) { + t.push(); + t.translate(-12 + i, 3); + t.char(i / 24 < progress ? '#' : '.'); + t.charColor(140, 220, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MILLIS3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESET MILLIS', x, y++, 100, 220, 255); + drawText('Space resets elapsed millis.', x, y++, 140, 160, 190); + drawText('Progress bar loops every 3s.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MS: ${Math.floor(t.millis)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` - ## Set Signature @@ -68,5 +221,55 @@ affect the value returned by [secs](secs.md) since they are connected. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.sin(t.millis * 0.002); + const angle = (value % 6.28) * 1; + t.push(); + t.translate(8, 2); + t.rotateZ((angle * 180) / Math.PI); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MILLIS4', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SMOOTH OSCILLATOR', x, y++, 100, 220, 255); + drawText('Numeric time drives motion.', x, y++, 140, 160, 190); + drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/overlay.md b/api/textmode.js/classes/Textmodifier/accessors/overlay.md index 256d147a..67ca6537 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/overlay.md +++ b/api/textmode.js/classes/Textmodifier/accessors/overlay.md @@ -31,5 +31,91 @@ Overlay source image for the target canvas or video, when overlay mode is enable ### Example - +```javascript +const sourceCanvas = document.createElement('canvas'); +const sourceCtx = sourceCanvas.getContext('2d'); + +document.body.style.margin = '0'; +document.body.style.overflow = 'hidden'; +sourceCanvas.style.position = 'fixed'; +sourceCanvas.style.inset = '0'; +sourceCanvas.style.width = '100vw'; +sourceCanvas.style.height = '100vh'; +sourceCanvas.style.display = 'block'; +document.body.appendChild(sourceCanvas); + +const t = textmode.create({ + canvas: sourceCanvas, + overlay: true, + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function resizeSourceCanvas() { + sourceCanvas.width = window.innerWidth; + sourceCanvas.height = window.innerHeight; +} + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function paintSourceCanvas() { + const pulse = t.frameCount * 0.035; + sourceCtx.fillStyle = '#050816'; + sourceCtx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); + sourceCtx.fillStyle = '#38bdf8'; + sourceCtx.fillRect(sourceCanvas.width * 0.24 + Math.sin(pulse) * 30, sourceCanvas.height * 0.42, 128, 82); + sourceCtx.fillStyle = '#f59e0b'; + sourceCtx.beginPath(); + sourceCtx.arc(sourceCanvas.width * 0.68, sourceCanvas.height * 0.5, 54, 0, Math.PI * 2); + sourceCtx.fill(); + sourceCtx.fillStyle = '#f8fafc'; + sourceCtx.fillRect(sourceCanvas.width * 0.33, sourceCanvas.height * 0.68, 150, 28); +} + +resizeSourceCanvas(); + +t.setup(() => { + if (!t.overlay) return; + t.overlay.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#050816'); +}); + +t.draw(() => { + paintSourceCanvas(); + t.clear(); + if (!t.overlay) return; + + t.image(t.overlay, t.grid.cols, t.grid.rows); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.OVERLAY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TARGET CANVAS SOURCE', x, y++, 100, 220, 255); + drawText('overlay samples sourceCanvas.', x, y++, 140, 160, 190); + drawText('Textmode renders above it.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = t.overlay ? 'READY' : 'WAIT'; + drawText(`OVERLAY: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + resizeSourceCanvas(); + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/secs.md b/api/textmode.js/classes/Textmodifier/accessors/secs.md index cd59966f..b284467d 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/secs.md +++ b/api/textmode.js/classes/Textmodifier/accessors/secs.md @@ -38,9 +38,110 @@ Seconds since the sketch started. ### Examples - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = t.secs; + const angle = (value % 6.28) * 1; + t.push(); + t.translate(8, 2); + t.rotateZ((angle * 180) / Math.PI); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SECS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ELAPSED SECONDS', x, y++, 100, 220, 255); + drawText('Numeric time drives motion.', x, y++, 140, 160, 190); + drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = t.secs % 4; + const angle = (value % 6.28) * 1; + t.push(); + t.translate(8, 2); + t.rotateZ((angle * 180) / Math.PI); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SECS2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOOPING SECONDS', x, y++, 100, 220, 255); + drawText('Numeric time drives motion.', x, y++, 140, 160, 190); + drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` - ## Set Signature @@ -65,5 +166,58 @@ affect the value returned by [millis](millis.md) since they are connected. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let scrub = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseDragged(() => { + scrub = t.mouse.x === Number.NEGATIVE_INFINITY ? scrub : t.mouse.x / 10; +}); + +t.draw(() => { + t.background(6, 10, 22); + const value = t.mouseIsPressed ? scrub : t.secs; + t.push(); + t.translate(8, 2); + t.rotateZ(value * 40); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(10, 2); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SECS3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCRUB TIME', x, y++, 100, 220, 255); + drawText('Drag to scrub temporary time.', x, y++, 140, 160, 190); + drawText('Release to resume t.secs.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SECS: ${t.secs.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/width.md b/api/textmode.js/classes/Textmodifier/accessors/width.md index 5b7d997b..8d8fee99 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/width.md +++ b/api/textmode.js/classes/Textmodifier/accessors/width.md @@ -28,5 +28,47 @@ Canvas width in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.char('='); + t.charColor(140, 220, 255); + t.rect(t.grid.cols, 1); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.WIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CANVAS WIDTH', x, y++, 100, 220, 255); + drawText('Returns pixel width.', x, y++, 140, 160, 190); + drawText('Line spans grid columns.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`WIDTH: ${t.width}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/abs.md b/api/textmode.js/classes/Textmodifier/methods/abs.md index c7e97159..a6fdd1f0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/abs.md +++ b/api/textmode.js/classes/Textmodifier/methods/abs.md @@ -34,5 +34,74 @@ Absolute value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let magnitude = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 7, 16); + raw = t.sin(t.frameCount * 0.045) * 12 + t.cos(t.frameCount * 0.021) * 3; + magnitude = t.abs(raw); + + t.char('-'); + t.charColor(60, 85, 125); + t.line(-24, 0, 24, 0); + t.char('|'); + t.line(0, -10, 0, 10); + + for (let i = 0; i <= t.round(magnitude); i++) { + const fade = t.norm(i, 0, 12); + t.push(); + t.translate(i, -5); + t.char('#'); + t.charColor(90 + fade * 150, 190, 255 - fade * 90); + t.point(); + t.translate(-i * 2, 10); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(255, 150, 110); + t.push(); + t.translate(t.round(raw), 0); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ABS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISTANCE FROM ZERO', x, y++, 100, 220, 255); + drawText('abs() removes the sign.', x, y++, 140, 160, 190); + drawText('Both sides draw equal magnitude.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`ABS: ${magnitude.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/acos.md b/api/textmode.js/classes/Textmodifier/methods/acos.md index 0b469273..79d9cab9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/acos.md +++ b/api/textmode.js/classes/Textmodifier/methods/acos.md @@ -34,5 +34,69 @@ Angle in radians. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let input = 0; +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(8, 7, 16); + input = t.constrain(t.cos(t.frameCount * 0.035) + t.sin(t.frameCount * 0.019) * 0.25, -1, 1); + angle = t.acos(input); + const radius = 15; + const x = t.round(input * radius); + const y = t.round(t.sin(angle) * radius); + + t.char('.'); + t.charColor(45, 65, 100); + for (let i = 0; i <= 36; i++) { + const a = t.radians(i * 5); + t.push(); + t.translate(t.round(t.cos(a) * radius), t.round(t.sin(a) * radius)); + t.point(); + t.pop(); + } + + t.char('|'); + t.charColor(95, 145, 210); + t.line(x, 0, x, y); + t.char('*'); + t.charColor(255, 205, 100); + t.line(0, 0, x, y); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ACOS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: X VALUE TO ANGLE', x, y++, 100, 220, 255); + drawText('acos(value) reverses cosine.', x, y++, 140, 160, 190); + drawText('The vertical chord reveals arc.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${input.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md index 290eada5..12cb54b7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md @@ -39,7 +39,59 @@ Lighting uses RGB only, so any provided alpha value is ignored. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let channel = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + channel = 127.5 + 127.5 * Math.sin(time); + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + t.ambientLight(channel, channel, channel, channel); + t.rotateY(time * 40); + t.char('#'); + t.charColor(255, 255, 255); + t.sphere(7); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.AMBIENTLIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: AMBIENT LIGHT', x, y++, 100, 220, 255); + drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); + drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const level = Math.round(channel); + drawText(`RGBA:${level},${level},${level},${level}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md index 2e739e3d..4923ff62 100644 --- a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md @@ -36,7 +36,57 @@ Current implementation supports affine TRS-style matrices (no perspective/shear) ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + const c = Math.cos(time); + const s = Math.sin(time); + t.push(); + t.translate(8, 1); + t.applyMatrix(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.APPLYMATRIX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM MATRIX', x, y++, 100, 220, 255); + drawText('Applies a 4x4 transform.', x, y++, 140, 160, 190); + drawText('Matrix rotates the rectangle.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.applyMatrix(...)', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/arc.md b/api/textmode.js/classes/Textmodifier/methods/arc.md index 0f3d4ca8..44a7a1aa 100644 --- a/api/textmode.js/classes/Textmodifier/methods/arc.md +++ b/api/textmode.js/classes/Textmodifier/methods/arc.md @@ -40,5 +40,59 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let startDeg = 0; +let endDeg = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + startDeg = (time * 60) % 360; + endDeg = startDeg + 110 + Math.sin(time) * 35; + t.push(); + t.translate(8, 1); + t.char('#'); + t.charColor(140, 180, 255); + t.arc(22, 12, startDeg, endDeg); + t.charColor(60, 70, 100); + t.line(0, 0, Math.cos((startDeg * Math.PI) / 180) * 11, Math.sin((startDeg * Math.PI) / 180) * 6); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ARC', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PARTIAL ELLIPSE', x, y++, 100, 220, 255); + drawText('Animated start and end angles.', x, y++, 140, 160, 190); + drawText('Guide line marks the start.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`START: ${startDeg.toFixed(1)}`, x, y++, 255, 210, 120); + drawText(`END: ${endDeg.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/asin.md b/api/textmode.js/classes/Textmodifier/methods/asin.md index ae850bc9..dbf91b36 100644 --- a/api/textmode.js/classes/Textmodifier/methods/asin.md +++ b/api/textmode.js/classes/Textmodifier/methods/asin.md @@ -34,5 +34,67 @@ Angle in radians. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let input = 0; +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 10, 18); + input = t.constrain(t.sin(t.frameCount * 0.04) + t.cos(t.frameCount * 0.017) * 0.25, -1, 1); + angle = t.asin(input); + const radius = 14; + + for (let i = -16; i <= 16; i++) { + const a = t.radians(i * 6); + t.push(); + t.translate(t.round(t.cos(a) * radius), t.round(t.sin(a) * radius)); + t.char('.'); + t.charColor(50, 70, 105); + t.point(); + t.pop(); + } + + t.char('-'); + t.charColor(80, 130, 180); + t.line(-radius, t.round(input * radius), radius, t.round(input * radius)); + t.char('*'); + t.charColor(255, 210, 100); + t.line(0, 0, t.round(t.cos(angle) * radius), t.round(t.sin(angle) * radius)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ASIN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VALUE BACK TO ANGLE', x, y++, 100, 220, 255); + drawText('asin(value) reverses sine.', x, y++, 140, 160, 190); + drawText('The horizontal value finds a ray.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${input.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/atan.md b/api/textmode.js/classes/Textmodifier/methods/atan.md index d0af2c41..395ba76e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan.md @@ -34,5 +34,67 @@ Angle in radians. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let slope = 0; +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + slope = t.sin(t.frameCount * 0.035) * 3 + t.cos(t.frameCount * 0.021) * 1.2; + angle = t.atan(slope); + + for (let i = -4; i <= 4; i++) { + const s = i * 0.6; + const a = t.atan(s); + t.char('.'); + t.charColor(45, 65, 100); + t.line(0, 0, t.round(t.cos(a) * 18), t.round(t.sin(a) * 18)); + } + + t.char('*'); + t.charColor(255, 215, 100); + t.line(0, 0, t.round(t.cos(angle) * 20), t.round(t.sin(angle) * 20)); + t.char('@'); + t.push(); + t.translate(t.round(t.cos(angle) * 20), t.round(t.sin(angle) * 20)); + t.charColor(120, 255, 170); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ATAN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SLOPE TO ANGLE', x, y++, 100, 220, 255); + drawText('atan(slope) compresses extremes.', x, y++, 140, 160, 190); + drawText('Steep values still fit a ray.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SLOPE: ${slope.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/atan2.md b/api/textmode.js/classes/Textmodifier/methods/atan2.md index 88e5c82a..9caf12da 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan2.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan2.md @@ -35,5 +35,68 @@ Angle in radians. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + const targetX = t.sin(t.frameCount * 0.027) * 18 + t.cos(t.frameCount * 0.05) * 4; + const targetY = t.cos(t.frameCount * 0.039) * 8 + t.sin(t.frameCount * 0.043) * 3; + angle = t.atan2(targetY, targetX); + + t.char('.'); + t.charColor(45, 60, 95); + for (let i = 0; i < 40; i++) { + const a = (i / 40) * t.radians(360); + t.push(); + t.translate(t.round(t.cos(a) * 16), t.round(t.sin(a) * 8)); + t.point(); + t.pop(); + } + + t.char('*'); + t.charColor(255, 215, 100); + t.line(0, 0, t.round(t.cos(angle) * 22), t.round(t.sin(angle) * 11)); + t.char('@'); + t.charColor(120, 255, 170); + t.push(); + t.translate(t.round(targetX), t.round(targetY)); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ATAN2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POINTING AT A TARGET', x, y++, 100, 220, 255); + drawText('atan2(y, x) keeps quadrants.', x, y++, 140, 160, 190); + drawText('The ray tracks the green target.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ANGLE: ${angle.toFixed(2)} rad`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/background.md b/api/textmode.js/classes/Textmodifier/methods/background.md index 4e43d495..c9ef5c28 100644 --- a/api/textmode.js/classes/Textmodifier/methods/background.md +++ b/api/textmode.js/classes/Textmodifier/methods/background.md @@ -30,7 +30,58 @@ Current background color. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let r = 0; +let g = 0; +let b = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.03; + r = Math.round(40 + 30 * Math.sin(time)); + g = Math.round(30 + 30 * Math.sin(time + 2)); + b = Math.round(60 + 40 * Math.sin(time + 4)); + t.background(r, g, b); + t.char('#'); + t.charColor(240, 245, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BACKGROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CANVAS COLOR', x, y++, 100, 220, 255); + drawText('Sets and reads scene backdrop.', x, y++, 140, 160, 190); + drawText('RGB values animate softly.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RGB: ${r},${g},${b}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,7 +104,53 @@ Set the background color using a grayscale value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let gray = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + gray = Math.round(30 + 40 * Math.sin(t.frameCount * 0.03)); + t.background(gray); + t.char('@'); + t.charColor(255, 210, 120); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BACKGROUND2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GRAY BACKGROUND', x, y++, 100, 220, 255); + drawText('One number sets R, G, and B.', x, y++, 140, 160, 190); + drawText('Gray value animates.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`GRAY: ${gray}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -82,7 +179,53 @@ Set the background color using RGB(A) values. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let useBlue = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + useBlue = Math.floor(t.frameCount / 90) % 2 === 0; + t.background(useBlue ? '#10183a' : '#301820'); + t.char(useBlue ? 'B' : 'R'); + t.charColor(255, 230, 140); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BACKGROUND3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HEX BACKGROUND', x, y++, 100, 220, 255); + drawText('Hex strings set the color.', x, y++, 140, 160, 190); + drawText('Mode alternates blue and red.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(useBlue ? 'HEX: BLUE' : 'HEX: RED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -104,5 +247,52 @@ Set the background color using a CSS string or TextmodeColor object. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const colorA = t.color(32, 12, 20); +const colorB = t.color(10, 24, 48); +let useA = true; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + useA = Math.floor(t.frameCount / 90) % 2 === 0; + t.background(useA ? colorA : colorB); + t.char(useA ? 'A' : 'B'); + t.charColor(255, 230, 140); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BACKGROUND4', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: COLOR OBJECT', x, y++, 100, 220, 255); + drawText('Reusable TextmodeColor values.', x, y++, 140, 160, 190); + drawText('Background switches objects.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(useA ? 'ACTIVE: COLOR A' : 'ACTIVE: COLOR B', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/beginShape.md b/api/textmode.js/classes/Textmodifier/methods/beginShape.md index 36cd1458..cd82d184 100644 --- a/api/textmode.js/classes/Textmodifier/methods/beginShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/beginShape.md @@ -33,5 +33,66 @@ Call [vertex](vertex.md) one or more times, then call [endShape](endShape.md) to ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let points = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.025; + const spikes = 7; + const outer = 16 + Math.sin(time) * 2; + const inner = 6 + Math.cos(time * 1.4) * 1.5; + points = spikes * 2; + + t.push(); + t.rotateZ(time * 18); + t.char('*'); + t.charColor(255, 220, 96); + t.cellColor(24, 16, 4); + t.lineWeight(1.4); + t.beginShape(); + for (let i = 0; i < points; i++) { + const angle = t.radians(i * (360 / points) - 90); + const radius = i % 2 === 0 ? outer : inner; + t.vertex(Math.cos(angle) * radius, Math.sin(angle) * radius); + } + t.endShape('close'); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BEGINSHAPE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM 2D POLYGON', x, y++, 100, 220, 255); + drawText('Recorded vertices form one loop.', x, y++, 140, 160, 190); + drawText('Line state is captured per vertex.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VERTICES: ${points}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md index 9c1dddd0..8e765cc5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md +++ b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md @@ -48,5 +48,59 @@ The curve thickness is controlled by the current [lineWeight](lineWeight.md) set ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.025; + const cp1x = -8 + Math.sin(time) * 6; + const cp1y = -7; + const cp2x = 8 + Math.cos(time * 0.8) * 6; + const cp2y = 7; + t.push(); + t.translate(7, 1); + t.charColor(60, 70, 100); + t.char('.'); + t.line(-14, 0, cp1x, cp1y); + t.line(14, 0, cp2x, cp2y); + t.char('#'); + t.charColor(140, 220, 255); + t.bezierCurve(-14, 0, cp1x, cp1y, cp2x, cp2y, 14, 0); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BEZIERCURVE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUBIC CURVE', x, y++, 100, 220, 255); + drawText('Two control points bend path.', x, y++, 140, 160, 190); + drawText('Guide lines show handles.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.bezierCurve(...)', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/box.md b/api/textmode.js/classes/Textmodifier/methods/box.md index 727df7a6..126799eb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/box.md +++ b/api/textmode.js/classes/Textmodifier/methods/box.md @@ -37,5 +37,61 @@ Draw a box mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.box(9, 7, 8); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BOX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D BOX', x, y++, 100, 220, 255); + drawText('Width, height, and depth vary.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/camera.md b/api/textmode.js/classes/Textmodifier/methods/camera.md index 7ed9d365..e13b5ed5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/camera.md +++ b/api/textmode.js/classes/Textmodifier/methods/camera.md @@ -49,5 +49,58 @@ Set an explicit camera transform for subsequent draw calls. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let eyeX = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + eyeX = Math.sin(time) * 24; + t.perspective(58, 0.1, 4096); + t.camera(eyeX, 8, 42, 0, 0, 0); + t.ambientLight(25, 28, 36); + t.pointLight([255, 210, 140], { x: 20, y: -18, z: 28 }); + t.push(); + t.rotateY(time * 30); + t.char('#'); + t.charColor(140, 220, 255); + t.box(8, 8, 8); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CAMERA', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET VIEW CAMERA', x, y++, 100, 220, 255); + drawText('Eye position moves left/right.', x, y++, 140, 160, 190); + drawText('Target remains at origin.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`EYE X: ${eyeX.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ceil.md b/api/textmode.js/classes/Textmodifier/methods/ceil.md index 8933adcb..9a852b60 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ceil.md +++ b/api/textmode.js/classes/Textmodifier/methods/ceil.md @@ -34,5 +34,63 @@ Smallest integer greater than or equal to the value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let snapped = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(7, 6, 17); + raw = t.norm(t.sin(t.frameCount * 0.045) + t.cos(t.frameCount * 0.017) * 0.25, -1.25, 1.25) * 14; + snapped = t.ceil(raw); + + for (let i = 0; i < 15; i++) { + const active = i < snapped; + t.push(); + t.translate(-16 + i * 2, 6 - i * 0.35); + t.char(active ? '#' : '.'); + t.charColor(active ? 120 + i * 8 : 50, active ? 245 : 65, active ? 170 : 95); + t.rect(1, active ? 2 + i * 0.2 : 1); + t.pop(); + } + + t.char('-'); + t.charColor(255, 150, 120); + t.line(-18, 8 - raw, 16, 8 - raw); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CEIL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SNAP UP', x, y++, 100, 220, 255); + drawText('ceil() counts partial cells full.', x, y++, 140, 160, 190); + drawText('Green blocks anticipate growth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`CEIL: ${snapped}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cellColor.md b/api/textmode.js/classes/Textmodifier/methods/cellColor.md index 5e9bd742..b0c66b86 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cellColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cellColor.md @@ -30,7 +30,54 @@ Current cell color. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + t.cellColor(value, 50, 110); + t.charColor(240, 245, 255); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CELLCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CELL BACKGROUND', x, y++, 100, 220, 255); + drawText('Sets the cell background color.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`R: ${value}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,7 +100,54 @@ Set the cell background color using a grayscale value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + t.cellColor(value); + t.charColor(240, 245, 255); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CELLCOLOR2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GRAY CELL BACKGROUND', x, y++, 100, 220, 255); + drawText('One number sets cellColor.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`GRAY: ${value}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -82,7 +176,54 @@ Set the cell background color using RGB(A) values. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + t.cellColor(value > 80 ? '#14385f' : '#301820'); + t.charColor(240, 245, 255); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CELLCOLOR3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HEX CELL BACKGROUND', x, y++, 100, 220, 255); + drawText('Hex strings set cellColor.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(value > 80 ? 'HEX: BLUE' : 'HEX: RED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -104,5 +245,52 @@ Set the cell background color using a CSS string or TextmodeColor object. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + const c = t.color(value, 40, 90); + t.cellColor(c); + t.charColor(240, 245, 255); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CELLCOLOR4', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CELL COLOR OBJECT', x, y++, 100, 220, 255); + drawText('TextmodeColor can be reused.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`R: ${value}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/char.md b/api/textmode.js/classes/Textmodifier/methods/char.md index aad5b9dc..9ef21c7d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/char.md +++ b/api/textmode.js/classes/Textmodifier/methods/char.md @@ -30,7 +30,54 @@ The active character string. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const glyphs = ['A', 'B', 'C', '#']; +let glyph = 'A'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + glyph = glyphs[Math.floor(t.frameCount / 45) % glyphs.length]; + t.char(glyph); + t.charColor(255, 210, 120); + t.rect(8, 4); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CHAR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACTIVE GLYPH', x, y++, 100, 220, 255); + drawText('Sets the glyph for drawing.', x, y++, 140, 160, 190); + drawText('The selected glyph cycles.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CHAR: ' + glyph, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,5 +100,50 @@ Accepts a single character string or a character index in the current font. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let index = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + index = Math.floor(t.frameCount / 5) % 128; + t.char(index); + t.charColor(255, 210, 120); + t.rect(8, 4); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CHAR2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH INDEX', x, y++, 100, 220, 255); + drawText('Numeric indices select glyphs.', x, y++, 140, 160, 190); + drawText('Index cycles through the font.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INDEX: ${index}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/charColor.md b/api/textmode.js/classes/Textmodifier/methods/charColor.md index d76fffa8..87a560e5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/charColor.md @@ -30,7 +30,56 @@ Current character color. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let current = t.color(255, 255, 255); + +t.draw(() => { + t.background(6, 10, 22); + const r = Math.round(150 + 105 * Math.sin(t.frameCount * 0.04)); + const g = Math.round(150 + 105 * Math.cos(t.frameCount * 0.03)); + t.charColor(r, g, 180); + current = t.charColor(); + t.char('#'); + t.rect(14, 6); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CHARCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CHARACTER COLOR', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const rgb = current.r + ',' + current.g + ',' + current.b; + drawText(`RGB: ${rgb}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,7 +102,53 @@ Set the character color using a grayscale value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + t.charColor(value, 220); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CHARCOLOR2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GRAY GLYPH COLOR', x, y++, 100, 220, 255); + drawText('Gray plus alpha overload.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`GRAY: ${value}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -82,7 +177,53 @@ Set the character color using RGB(A) values. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + t.charColor(value > 80 ? '#facc15' : '#38bdf8'); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CHARCOLOR3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HEX GLYPH COLOR', x, y++, 100, 220, 255); + drawText('Hex strings color glyphs.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(value > 80 ? 'HEX: GOLD' : 'HEX: CYAN', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -104,5 +245,54 @@ Set the character color using a CSS string or TextmodeColor object. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const colorA = t.color('#64ffd0'); +const colorB = t.color('#ffc878'); +let active = 'colorA'; + +t.draw(() => { + t.background(6, 10, 22); + const useA = Math.floor(t.frameCount / 45) % 2 === 0; + active = useA ? 'colorA' : 'colorB'; + t.charColor(useA ? colorA : colorB); + t.char('@'); + t.rotateZ(t.frameCount * 2); + t.rect(10, 10); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CHARCOLOR4', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: COLOR OBJECT INPUT', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ACTIVE: ${active}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/charRotation.md b/api/textmode.js/classes/Textmodifier/methods/charRotation.md index 42ba0b81..5223552d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charRotation.md +++ b/api/textmode.js/classes/Textmodifier/methods/charRotation.md @@ -34,5 +34,56 @@ Current rotation angle in degrees when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + angle = (t.frameCount * 2) % 360; + for (let i = 0; i < 8; i++) { + t.push(); + t.translate((i - 3.5) * 3, 0); + t.charRotation(angle + i * 30); + t.char('+'); + t.charColor(140, 220, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CHARROTATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ROTATE GLYPHS', x, y++, 100, 220, 255); + drawText('Rotates characters in cells.', x, y++, 140, 160, 190); + drawText('Transform matrix is unchanged.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ANGLE: ${angle}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/clamp.md b/api/textmode.js/classes/Textmodifier/methods/clamp.md index ef560d34..b79ff75c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/clamp.md @@ -41,5 +41,96 @@ The clamped value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let clamped = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(8, 9, 17); + const low = -10; + const high = 10; + const railWidth = high - low + 1; + raw = Math.sin(t.frameCount * 0.045) * 18 + t.mouse.x * 0.28; + clamped = t.clamp(raw, low, high); + + t.char('.'); + t.charColor(38, 50, 80); + for (let x = -22; x <= 22; x += 2) drawPoint(x, 0); + + drawBand((low + high) / 2, -5, railWidth, 1, 80, 130, 190); + drawBand((low + high) / 2, 5, railWidth, 1, 80, 130, 190); + drawBand(low, 0, 1, 11, 55, 120, 155); + drawBand(high, 0, 1, 11, 55, 120, 155); + + t.push(); + t.translate(raw, -5); + t.char('o'); + t.charColor(230, 90, 90); + t.point(); + t.pop(); + + t.push(); + t.translate(clamped, 0); + t.char('#'); + t.charColor(110, 245, 170); + t.rect(2, 11); + t.pop(); + + t.char('*'); + t.charColor(255, 205, 90); + t.line(raw, -5, clamped, 0); + t.line(raw, 5, clamped, 0); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CLAMP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HARD LIMITS', x, y++, 100, 220, 255); + drawText('Raw red input can leave the gate.', x, y++, 140, 160, 190); + drawText('clamp() pins output to the rails.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(1)}`, x, y++, 255, 150, 120); + drawText(`CLAMPED: ${clamped.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/clear.md b/api/textmode.js/classes/Textmodifier/methods/clear.md index 3cb7ad90..4413c6cd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clear.md +++ b/api/textmode.js/classes/Textmodifier/methods/clear.md @@ -28,5 +28,60 @@ Used to clear the layer at the start of its drawing cycle. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let clearEnabled = true; + +t.mouseClicked(() => { + clearEnabled = !clearEnabled; + if (clearEnabled) t.clear(); +}); + +t.draw(() => { + if (clearEnabled) t.clear(); + const time = t.frameCount * 0.05; + t.push(); + t.translate(Math.cos(time) * 15, Math.sin(time) * 6); + t.charColor(255, 225, 140); + t.char('#'); + t.rect(4, 2); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CLEAR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLEAR LAYER BUFFER', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = clearEnabled ? 'ON' : 'OFF'; + drawText(`CLEAR: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/color.md b/api/textmode.js/classes/Textmodifier/methods/color.md index 1d5c2dd8..cc37b2f1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/color.md +++ b/api/textmode.js/classes/Textmodifier/methods/color.md @@ -37,7 +37,54 @@ A TextmodeColor instance ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + const c = t.color(value, 180); + t.charColor(c); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MAKE COLOR', x, y++, 100, 220, 255); + drawText('Creates reusable gray color.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -68,7 +115,62 @@ A TextmodeColor instance ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const goldLayer = t.layers.add(); +const cyan = t.color(100, 220, 255); +const gold = t.color(255, 225, 140, 150); + +t.draw(() => { + t.background(6, 10, 22); + t.charColor(cyan); + t.char('o'); + t.translate(Math.cos(t.frameCount * 0.03) * 10, 0); + t.ellipse(12, 10); +}); + +goldLayer.draw(() => { + t.clear(); + t.charColor(gold); + t.char('#'); + t.rect(12, 8); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.COLOR2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RGBA COLOR OBJECT', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('RGBA ALPHA: 150', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -95,5 +197,51 @@ A TextmodeColor instance ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); + t.char('#'); + const c = t.color(value > 80 ? '#facc15' : '#38bdf8'); + t.charColor(c); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COLOR3', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HEX COLOR', x, y++, 100, 220, 255); + drawText('Creates color from hex string.', x, y++, 140, 160, 190); + drawText('The value pulses every frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(value > 80 ? 'HEX: GOLD' : 'HEX: CYAN', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/colorMode.md b/api/textmode.js/classes/Textmodifier/methods/colorMode.md index b9bab9bf..10faba1d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/colorMode.md +++ b/api/textmode.js/classes/Textmodifier/methods/colorMode.md @@ -30,7 +30,103 @@ Current color mode and channel maxes. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const glyphs = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.colorMode('rgb'); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function paintCell(mode, u, v, wave, curl, hue) { + const shimmer = (wave + curl) * 0.5; + if (mode === 'rgb') { + t.colorMode('rgb', 255); + t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); + t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); + return; + } + if (mode === 'hsb') { + t.colorMode('hsb', 360, 100, 100, 1); + t.cellColor(hue, 92, 2 + 24 * wave); + t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); + return; + } + t.colorMode('hsl', 360, 100, 100, 1); + t.cellColor(hue, 65, 8 + 45 * curl); + t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); +} + +function paintPanel(mode, index, left, top, panelWidth, height, time) { + const x0 = left + index * panelWidth; + const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; + const y0 = top + 11; + for (let y = y0; y < top + height - 2; y++) { + t.push(); + t.translate(x0, y); + for (let x = x0; x < x1; x++) { + const u = (x - x0) / Math.max(1, x1 - x0 - 1); + const v = (y - y0) / Math.max(1, height - 13); + const dx = u * 2 - 1; + const dy = v * 2 - 1; + const radius = Math.sqrt(dx * dx + dy * dy); + const angle = Math.atan2(dy, dx); + const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; + const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; + const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; + const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; + t.char(glyph); + paintCell(mode, u, v, wave, curl, hue); + t.point(); + t.translate(1, 0); + } + t.pop(); + } +} + +t.draw(() => { + t.colorMode('rgb'); + t.background(4, 6, 14); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const panelWidth = Math.floor(t.grid.cols / 3); + const time = t.frameCount * 0.035; + paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); + drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); + drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); + drawText('Same hue, different third value.', x, y++, 140, 160, 190); + drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -57,7 +153,103 @@ alpha, defaulting to the selected mode's alpha max. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const glyphs = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.colorMode('rgb'); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function paintCell(mode, u, v, wave, curl, hue) { + const shimmer = (wave + curl) * 0.5; + if (mode === 'rgb') { + t.colorMode('rgb', 255); + t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); + t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); + return; + } + if (mode === 'hsb') { + t.colorMode('hsb', 360, 100, 100, 1); + t.cellColor(hue, 92, 2 + 24 * wave); + t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); + return; + } + t.colorMode('hsl', 360, 100, 100, 1); + t.cellColor(hue, 65, 8 + 45 * curl); + t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); +} + +function paintPanel(mode, index, left, top, panelWidth, height, time) { + const x0 = left + index * panelWidth; + const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; + const y0 = top + 11; + for (let y = y0; y < top + height - 2; y++) { + t.push(); + t.translate(x0, y); + for (let x = x0; x < x1; x++) { + const u = (x - x0) / Math.max(1, x1 - x0 - 1); + const v = (y - y0) / Math.max(1, height - 13); + const dx = u * 2 - 1; + const dy = v * 2 - 1; + const radius = Math.sqrt(dx * dx + dy * dy); + const angle = Math.atan2(dy, dx); + const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; + const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; + const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; + const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; + t.char(glyph); + paintCell(mode, u, v, wave, curl, hue); + t.point(); + t.translate(1, 0); + } + t.pop(); + } +} + +t.draw(() => { + t.colorMode('rgb'); + t.background(4, 6, 14); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const panelWidth = Math.floor(t.grid.cols / 3); + const time = t.frameCount * 0.035; + paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); + drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); + drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); + drawText('Same hue, different third value.', x, y++, 140, 160, 190); + drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -88,5 +280,100 @@ Set how numeric color inputs are interpreted with per-channel ranges. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const glyphs = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.colorMode('rgb'); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function paintCell(mode, u, v, wave, curl, hue) { + const shimmer = (wave + curl) * 0.5; + if (mode === 'rgb') { + t.colorMode('rgb', 255); + t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); + t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); + return; + } + if (mode === 'hsb') { + t.colorMode('hsb', 360, 100, 100, 1); + t.cellColor(hue, 92, 2 + 24 * wave); + t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); + return; + } + t.colorMode('hsl', 360, 100, 100, 1); + t.cellColor(hue, 65, 8 + 45 * curl); + t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); +} + +function paintPanel(mode, index, left, top, panelWidth, height, time) { + const x0 = left + index * panelWidth; + const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; + const y0 = top + 11; + for (let y = y0; y < top + height - 2; y++) { + t.push(); + t.translate(x0, y); + for (let x = x0; x < x1; x++) { + const u = (x - x0) / Math.max(1, x1 - x0 - 1); + const v = (y - y0) / Math.max(1, height - 13); + const dx = u * 2 - 1; + const dy = v * 2 - 1; + const radius = Math.sqrt(dx * dx + dy * dy); + const angle = Math.atan2(dy, dx); + const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; + const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; + const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; + const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; + t.char(glyph); + paintCell(mode, u, v, wave, curl, hue); + t.point(); + t.translate(1, 0); + } + t.pop(); + } +} + +t.draw(() => { + t.colorMode('rgb'); + t.background(4, 6, 14); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const panelWidth = Math.floor(t.grid.cols / 3); + const time = t.frameCount * 0.035; + paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); + paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); + drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); + drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); + drawText('Same hue, different third value.', x, y++, 140, 160, 190); + drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cone.md b/api/textmode.js/classes/Textmodifier/methods/cone.md index d7fb7e06..746e3c6b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cone.md +++ b/api/textmode.js/classes/Textmodifier/methods/cone.md @@ -33,5 +33,61 @@ Draw a cone mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.cone(5, 12); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CONE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D CONE', x, y++, 100, 220, 255); + drawText('Radius and height define form.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/constrain.md b/api/textmode.js/classes/Textmodifier/methods/constrain.md index cdb8d3d0..df0e0c71 100644 --- a/api/textmode.js/classes/Textmodifier/methods/constrain.md +++ b/api/textmode.js/classes/Textmodifier/methods/constrain.md @@ -39,5 +39,94 @@ The constrained value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let freeX = 0; +let boundedX = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(7, 11, 18); + const leftRail = -14; + const rightRail = 14; + const railWidth = rightRail - leftRail + 1; + freeX = Math.cos(t.frameCount * 0.035) * 20 + t.mouse.x * 0.18; + boundedX = t.constrain(freeX, leftRail, rightRail); + + drawBand((leftRail + rightRail) / 2, -7, railWidth, 1, 54, 70, 100); + drawBand((leftRail + rightRail) / 2, 7, railWidth, 1, 54, 70, 100); + drawBand(leftRail, 0, 1, 15, 90, 165, 215); + drawBand(rightRail, 0, 1, 15, 90, 165, 215); + + for (let i = 0; i < 9; i++) { + const y = -6 + i * 1.5; + const offset = Math.sin(t.frameCount * 0.04 + i) * 2; + const x = t.constrain(boundedX + offset, leftRail, rightRail); + const heat = Math.round(t.constrain(Math.abs(freeX - boundedX) * 20, 0, 255)); + t.char(i % 2 === 0 ? '*' : '+'); + t.charColor(255 - heat * 0.4, 170 + heat * 0.2, 120 + heat * 0.5); + drawPoint(x, y); + } + + t.push(); + t.translate(freeX, -9); + t.char('x'); + t.charColor(255, 95, 95); + t.point(); + t.pop(); + + t.char('.'); + t.charColor(255, 220, 120); + t.line(freeX, -9, boundedX, -7); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CONSTRAIN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RANGE SAFETY', x, y++, 100, 220, 255); + drawText('constrain() keeps motion in bounds.', x, y++, 140, 160, 190); + drawText('The red target may drift outside.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FREE X: ${freeX.toFixed(1)}`, x, y++, 255, 150, 120); + drawText(`SAFE X: ${boundedX.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cos.md b/api/textmode.js/classes/Textmodifier/methods/cos.md index e7c27268..abaedc09 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cos.md +++ b/api/textmode.js/classes/Textmodifier/methods/cos.md @@ -36,5 +36,67 @@ Cosine of the angle. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let phase = 0; +let sample = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 15); + phase = t.frameCount * 0.045; + sample = t.cos(phase); + const rings = 9; + + for (let i = rings; i >= 1; i--) { + const wave = t.norm(t.cos(phase + i * 0.45), -1, 1); + const rx = 2 + i * 3 + wave * 3; + const ry = 1 + i * 1.2 + wave * 2; + t.push(); + t.char(i % 2 === 0 ? '.' : '+'); + t.charColor(70 + wave * 140, 120 + wave * 90, 230); + t.ellipse(rx, ry); + t.pop(); + } + + t.push(); + t.translate(t.round(sample * 18), 0); + t.char('@'); + t.charColor(255, 215, 110); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.COS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PHASED BREATHING', x, y++, 100, 220, 255); + drawText('cos() starts at 1, then cycles.', x, y++, 140, 160, 190); + drawText('Rings expand by cosine phase.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`COS: ${sample.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createCamera.md b/api/textmode.js/classes/Textmodifier/methods/createCamera.md index ea025dd7..bdc10d38 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/createCamera.md @@ -29,5 +29,62 @@ reapplied via [setCamera](setCamera.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let camera; +let eyeX = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + t.perspective(58, 0.1, 4096); + camera = t.createCamera(); +}); + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + eyeX = Math.cos(time) * 28; + camera.setPosition(eyeX, 10, 38).lookAt(0, 0, 0); + t.setCamera(camera); + t.ambientLight(25, 28, 36); + t.pointLight([255, 210, 140], { x: 18, y: -16, z: 28 }); + t.rotateY(time * 25); + t.char('@'); + t.charColor(140, 220, 255); + t.sphere(6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CREATECAMERA', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MUTABLE CAMERA', x, y++, 100, 220, 255); + drawText('createCamera returns an object.', x, y++, 140, 160, 190); + drawText('setCamera applies its state.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`EYE X: ${eyeX.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md b/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md index d493c89a..4e8b668c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md @@ -42,5 +42,80 @@ This compatibility alias creates a fragment-only geometry shader for use with ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let shaderObj; +let glyphA = [0, 0, 0]; +let glyphB = [0, 0, 0]; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} +t.setup(async () => { + glyphA = t.font.characterMap.get('#')?.color ?? t.font.characters[1].color; + glyphB = t.font.characterMap.get('@')?.color ?? t.font.characters[2].color; + shaderObj = await t.createFilterShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +uniform vec3 u_glyphA; +uniform vec3 u_glyphB; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + float stripe = step(0.5, fract((v_uv.x + u_time) * 10.0)); + vec3 glyphId = mix(u_glyphA, u_glyphB, stripe); + vec3 primary = mix(vec3(0.3, 0.8, 1.0), vec3(1.0, 0.42, 0.22), stripe); + o_character = vec4(glyphId.xy, 0.0, 0.0); + o_primaryColor = vec4(primary, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.08 + stripe * 0.12, 1.0); +}`); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (shaderObj) { + const time = t.frameCount * 0.02; + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + t.shader(shaderObj); + t.setUniforms({ u_time: time * 0.1, u_glyphA: glyphA, u_glyphB: glyphB }); + t.push(); + t.rotateZ(time * 40); + t.rect(16, 8); + t.pop(); + t.resetShader(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CREATEFILTERSHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: COMPAT ALIAS', x, y++, 100, 220, 255); + drawText('Use createMaterialShader now.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(shaderObj ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md index 0c8d0353..00adccf2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md +++ b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md @@ -37,5 +37,54 @@ The created framebuffer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const fb = t.createFramebuffer({ width: 24, height: 14 }); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + fb.begin(); + t.clear(); + t.background(20, 30, 60); + t.char('#'); + t.charColor(255, 210, 120); + t.rect(12, 4); + fb.end(); + t.image(fb); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CREATEFRAMEBUFFER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: OFFSCREEN BUFFER', x, y++, 100, 220, 255); + drawText('Renders into a framebuffer.', x, y++, 140, 160, 190); + drawText('Then draws it to the scene.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SIZE: ${fb.width} x ${fb.height}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md index 7bee4320..a16c0f43 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md @@ -34,5 +34,61 @@ A TextmodeGlyphRamp instance. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const baseRamp = t.createGlyphRamp(' ░▒▓█'); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + + const ramp = baseRamp.shift(t.frameCount * 0.08); + for (let x = 0; x < t.grid.cols; x++) { + for (let y = 0; y < t.grid.rows; y++) { + const gx = x - Math.floor(t.grid.cols / 2); + const gy = y - Math.floor(t.grid.rows / 2); + const value = t.noise(x * 0.08, y * 0.12, t.secs * 0.3); + + t.push(); + t.translate(gx, gy); + t.charColor(80 + value * 140, 160 + value * 80, 230); + t.char(ramp.at(value)); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEGLYPHRAMP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH DENSITY RAMP', x, y++, 100, 220, 255); + drawText('Glyph strings create ramps.', x, y++, 140, 160, 190); + drawText('shift() cycles without mutating.', x, y++, 140, 160, 190); + drawText(`ramp: ${baseRamp.characters}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md index d9d2951e..8ae9d41b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md @@ -39,5 +39,80 @@ A compiled shader ready for use with [shader](shader.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let materialShader = null; +let glyphA = [0, 0, 0]; +let glyphB = [0, 0, 0]; + +t.setup(async () => { + glyphA = t.font.characterMap.get('#')?.color ?? t.font.characters[1].color; + glyphB = t.font.characterMap.get('@')?.color ?? t.font.characters[2].color; + materialShader = await t.createMaterialShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +uniform vec3 u_glyphA; +uniform vec3 u_glyphB; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + float rings = sin((distance(v_uv, vec2(0.5)) - u_time) * 32.0); + float glyph = step(0.0, rings); + vec3 glyphId = mix(u_glyphA, u_glyphB, glyph); + vec3 primary = mix(vec3(0.2, 0.8, 1.0), vec3(1.0, 0.45, 0.25), glyph); + o_character = vec4(glyphId.xy, 0.0, 0.0); + o_primaryColor = vec4(primary, 1.0); + o_secondaryColor = vec4(0.01, 0.02, 0.05, 1.0); +}`); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(0); + if (!materialShader) return; + const time = t.frameCount * 0.003; + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + t.shader(materialShader); + t.setUniforms({ u_time: time, u_glyphA: glyphA, u_glyphB: glyphB }); + t.rotateY(t.frameCount); + t.sphere(8); + t.resetShader(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEMATERIALSHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GEOMETRY SHADER', x, y++, 100, 220, 255); + drawText('Fragment shader affects shapes.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(materialShader ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createShader.md b/api/textmode.js/classes/Textmodifier/methods/createShader.md index bd8671ae..eac0f021 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createShader.md @@ -35,5 +35,69 @@ The compiled shader. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let shaderObj; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_texCoord; + out vec2 v_uv; + void main(){gl_Position=a_position;v_uv=a_texCoord;}`; + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform float u_time; + layout(location=0) out vec4 o_character; + layout(location=1) out vec4 o_primaryColor; + layout(location=2) out vec4 o_secondaryColor; + void main(){float v=fract(v_uv.x*8.0+u_time);o_character=vec4(v,0,0,1);o_primaryColor=vec4(v,0.8,1.0,1);o_secondaryColor=vec4(0.02,0.04,0.08,1);}`; + shaderObj = await t.createShader(vert, frag); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (shaderObj) { + t.shader(shaderObj); + t.setUniform('u_time', t.frameCount * 0.02); + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CREATESHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); + drawText('Shader affects the main drawing.', x, y++, 140, 160, 190); + drawText('resetShader restores default.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(shaderObj ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createTexture.md b/api/textmode.js/classes/Textmodifier/methods/createTexture.md index 7489a406..a3dd8c80 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/createTexture.md @@ -39,5 +39,59 @@ A TextmodeTexture that can be drawn with [image](image.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const sourceCanvas = document.createElement('canvas'); +sourceCanvas.width = 64; +sourceCanvas.height = 64; +const ctx = sourceCanvas.getContext('2d'); +let texture; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + texture = t.createTexture(sourceCanvas); +}); + +t.draw(() => { + t.background(6, 10, 22); + ctx.fillStyle = '#10183a'; + ctx.fillRect(0, 0, 64, 64); + ctx.fillStyle = '#facc15'; + ctx.fillRect(8 + (t.frameCount % 32), 20, 16, 16); + if (texture) t.image(texture, 24, 14); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CREATETEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CANVAS TEXTURE', x, y++, 100, 220, 255); + drawText('Wraps a 2D canvas source.', x, y++, 140, 160, 190); + drawText('Source canvas is animated.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(texture ? 'TEXTURE: READY' : 'TEXTURE: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/createVector.md b/api/textmode.js/classes/Textmodifier/methods/createVector.md index 655d8f95..3fe0a7b1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createVector.md +++ b/api/textmode.js/classes/Textmodifier/methods/createVector.md @@ -42,5 +42,97 @@ A new TextmodeVector instance. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const pos = t.createVector(-18, -6); +const vel = t.createVector(0.5, 0.12); +const acc = t.createVector(); +const target = t.createVector(); +const trail = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(point, char, r, g, b) { + t.push(); + t.translate(Math.round(point.x), Math.round(point.y)); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + + const time = t.frameCount * 0.045; + const radiusX = Math.max(8, t.grid.cols / 4); + const radiusY = Math.max(4, t.grid.rows / 4); + target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); + + const desired = target.copy().sub(pos); + const distance = desired.mag(); + const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); + const steer = desired.setMag(speed).sub(vel).limit(0.045); + + acc.set(steer); + vel.add(acc).limit(0.82); + pos.add(vel); + + trail.push(pos.copy()); + if (trail.length > 28) { + trail.shift(); + } + + for (let i = 0; i < trail.length; i++) { + const fade = i / trail.length; + const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; + plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); + } + + const ray = vel.copy().setMag(5); + for (let i = 1; i <= 5; i++) { + plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); + } + + plot(target, 'x', 255, 120, 150); + plot(target.copy().add(0, -1), '|', 255, 80, 120); + plot(target.copy().add(-1, 0), '-', 255, 80, 120); + plot(target.copy().add(1, 0), '-', 255, 80, 120); + plot(pos, '@', 110, 255, 170); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); + drawText('target - position makes desired.', x, y++, 140, 160, 190); + drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); + drawText('velocity and position use add().', x, y++, 140, 160, 190); + drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cursor.md b/api/textmode.js/classes/Textmodifier/methods/cursor.md index 460d0d66..a39dd6ed 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cursor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cursor.md @@ -38,5 +38,101 @@ See MDN for all options: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let currentCursor = 'default'; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(10, 12, 18); + const mx = t.mouse.x, + my = t.mouse.y; + const isInside = mx !== Number.NEGATIVE_INFINITY; + + if (isInside) { + if (mx < 0 && my < 0) currentCursor = 'crosshair'; + else if (mx >= 0 && my < 0) currentCursor = 'grab'; + else if (mx < 0 && my >= 0) currentCursor = 'not-allowed'; + else currentCursor = 'pointer'; + } else { + currentCursor = 'default'; + } + t.cursor(currentCursor); + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + for (let y = -hh + 1; y <= hh - 1; y += 1) { + for (let x = -hw + 1; x <= hw - 1; x += 1) { + const isTL = x < 0 && y < 0, + isTR = x >= 0 && y < 0; + const isBL = x < 0 && y >= 0, + isBR = x >= 0 && y >= 0; + const isActive = + isInside && + ((isTL && currentCursor === 'crosshair') || + (isTR && currentCursor === 'grab') || + (isBL && currentCursor === 'not-allowed') || + (isBR && currentCursor === 'pointer')); + + if (x === 0 || y === 0) { + t.push(); + t.translate(x, y); + t.charColor(40, 50, 75); + t.char(x === 0 && y === 0 ? '+' : x === 0 ? '|' : '-'); + t.point(); + t.pop(); + } else if (isActive) { + t.push(); + t.translate(x, y); + if (isTL) { + t.charColor(0, 229, 255); + t.cellColor(0, 40, 60); + t.char('+'); + } else if (isTR) { + t.charColor(0, 255, 136); + t.cellColor(0, 50, 30); + t.char('#'); + } else if (isBL) { + t.charColor(255, 51, 85); + t.cellColor(60, 0, 20); + t.char('X'); + } else { + t.charColor(255, 204, 0); + t.cellColor(60, 45, 0); + t.char('>'); + } + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.CURSOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DYNAMIC CURSOR SYNTHESIZER', x, y++, 100, 220, 255); + drawText('Updates cursor by hit-testing grid.', x, y++, 140, 160, 190); + drawText('Supports crosshair, grab & pointer.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ACTIVE CURSOR: ' + currentCursor.toUpperCase(), x, y++, 140, 255, 180); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cylinder.md b/api/textmode.js/classes/Textmodifier/methods/cylinder.md index ed72d96d..9fb7d85e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cylinder.md +++ b/api/textmode.js/classes/Textmodifier/methods/cylinder.md @@ -33,5 +33,61 @@ Draw a cylinder mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.cylinder(4, 12); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.CYLINDER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D CYLINDER', x, y++, 100, 220, 255); + drawText('Radius and height define form.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/degrees.md b/api/textmode.js/classes/Textmodifier/methods/degrees.md index 106c8750..ca8f4090 100644 --- a/api/textmode.js/classes/Textmodifier/methods/degrees.md +++ b/api/textmode.js/classes/Textmodifier/methods/degrees.md @@ -34,5 +34,82 @@ Angle in degrees. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let angleDeg = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(6, 12, 18); + const targetX = t.mouse.x || Math.cos(t.frameCount * 0.025) * 10; + const targetY = t.mouse.y || Math.sin(t.frameCount * 0.025) * 6; + const radians = Math.atan2(targetY, targetX); + angleDeg = t.degrees(radians); + + t.char('.'); + t.charColor(42, 58, 86); + t.ellipse(14, 14); + t.line(-10, 0, 10, 0); + t.line(0, -6, 0, 6); + + t.char('+'); + t.charColor(90, 170, 230); + for (let i = 0; i < 12; i++) { + const a = (i / 12) * Math.PI * 2; + drawPoint(Math.cos(a) * 7, Math.sin(a) * 7); + } + + t.push(); + t.rotate(angleDeg); + t.char('>'); + t.charColor(255, 210, 110); + t.line(0, 0, 8, 0); + t.translate(9, 0); + t.point(); + t.pop(); + + t.char('o'); + t.charColor(120, 255, 180); + drawPoint(targetX, targetY); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DEGREES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RADIAN TO DEGREE', x, y++, 100, 220, 255); + drawText('atan2() gives radians.', x, y++, 140, 160, 190); + drawText('degrees() feeds rotate().', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ANGLE: ${angleDeg.toFixed(1)} DEG`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md index a6411882..8e75eb6a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md +++ b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md @@ -32,5 +32,59 @@ Milliseconds elapsed since the previous frame. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let xPos = -18; +let dt = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + dt = t.deltaTime(); + xPos += dt * 0.01; + if (xPos > 18) xPos = -18; + t.charColor(60, 70, 100); + t.char('-'); + t.line(-18, 0, 18, 0); + t.push(); + t.translate(xPos, 0); + t.char('@'); + t.charColor(140, 255, 180); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DELTATIME', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FRAME ELAPSED MS', x, y++, 100, 220, 255); + drawText('Motion scales by deltaTime.', x, y++, 140, 160, 190); + drawText('Speed stays frame-rate aware.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DT: ${dt.toFixed(1)} MS`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/destroy.md b/api/textmode.js/classes/Textmodifier/methods/destroy.md index a2f192e5..38ffdfce 100644 --- a/api/textmode.js/classes/Textmodifier/methods/destroy.md +++ b/api/textmode.js/classes/Textmodifier/methods/destroy.md @@ -28,5 +28,54 @@ After calling this method, the instance should not be used and will be eligible ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let requested = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + requested = true; +}); + +t.draw(() => { + t.background(12, 6, 8); + t.char(requested ? '!' : '#'); + t.charColor(requested ? 255 : 140, requested ? 120 : 220, 120); + t.rect(12, 5); + if (requested && t.frameCount % 120 === 0) t.destroy(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DESTROY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISPOSE INSTANCE', x, y++, 100, 220, 255); + drawText('Click requests cleanup.', x, y++, 140, 160, 190); + drawText('Destroy runs on next cycle.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(requested ? 'REQUESTED: YES' : 'REQUESTED: NO', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/dist.md b/api/textmode.js/classes/Textmodifier/methods/dist.md index bdb7918b..b0d66757 100644 --- a/api/textmode.js/classes/Textmodifier/methods/dist.md +++ b/api/textmode.js/classes/Textmodifier/methods/dist.md @@ -41,5 +41,78 @@ The distance between the two points. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let distance = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(5, 10, 18); + const beaconX = Math.cos(t.frameCount * 0.025) * 8; + const beaconY = Math.sin(t.frameCount * 0.035) * 5; + distance = t.dist(beaconX, beaconY, t.mouse.x, t.mouse.y); + + for (let y = -10; y <= 10; y += 2) { + for (let x = -18; x <= 18; x += 2) { + const d = t.dist(x, y, beaconX, beaconY); + const shade = Math.round(t.constrain(t.map(d, 0, 20, 210, 35), 35, 210)); + t.char(d < 4 ? '*' : '.'); + t.charColor(60, shade, 255 - shade * 0.4); + drawPoint(x, y); + } + } + + t.char('o'); + t.charColor(255, 220, 120); + t.push(); + t.translate(beaconX, beaconY); + t.ellipse(8, 8); + t.point(); + t.pop(); + + t.char('+'); + t.charColor(120, 255, 180); + drawPoint(t.mouse.x, t.mouse.y); + t.line(beaconX, beaconY, t.mouse.x, t.mouse.y); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DIST', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POINT DISTANCE', x, y++, 100, 220, 255); + drawText('dist() measures between two points.', x, y++, 140, 160, 190); + drawText('Distance drives the field shading.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MOUSE RANGE: ${distance.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md index 44dea05a..88fdac90 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md @@ -32,5 +32,75 @@ Register the single-callback handler for double-clicks. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.doubleClicked(() => { + addPulse('DOUBLE CLICK', t.mouse.x, t.mouse.y); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DOUBLECLICKED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DOUBLE CLICK', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('DOUBLE: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md index d1260599..cdd75b5f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md @@ -35,5 +35,76 @@ helper lets you supply a dedicated handler when you want to treat double taps di ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.doubleTap((data) => { + const touch = data?.touch || t.mouse; + addPulse('DOUBLE', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DOUBLETAP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DOUBLE TAP', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('DOUBLE: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/draw.md b/api/textmode.js/classes/Textmodifier/methods/draw.md index 61ff2992..1ba9488e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/draw.md +++ b/api/textmode.js/classes/Textmodifier/methods/draw.md @@ -42,5 +42,53 @@ textmodifier.layers.base.draw(callback); ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let pulse = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + pulse = 0.5 + 0.5 * Math.sin(t.frameCount * 0.05); + t.push(); + t.translate(8, 2); + t.char('#'); + t.charColor(120, 120 + pulse * 120, 255); + t.rect(6 + pulse * 8, 3 + pulse * 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DRAW', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FRAME CALLBACK', x, y++, 100, 220, 255); + drawText('draw() runs every frame.', x, y++, 140, 160, 190); + drawText('Pulse proves continuous updates.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`PULSE: ${pulse.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ease.md b/api/textmode.js/classes/Textmodifier/methods/ease.md index 08eaf542..18cb1283 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ease.md +++ b/api/textmode.js/classes/Textmodifier/methods/ease.md @@ -38,5 +38,82 @@ Eased amount. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const duration = 120; +const curves = [ + { name: 'linear', char: 'o', y: -6, color: [120, 190, 255] }, + { name: 'inQuad', char: 'q', y: -3, color: [255, 210, 120] }, + { name: 'outSine', char: 's', y: 0, color: [255, 140, 180] }, + { name: 'inOutCubic', char: '@', y: 3, color: [120, 255, 170] }, + { name: 'outBounce', char: 'b', y: 6, color: [190, 160, 255] }, +]; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function plot(x, y, char, r, g, b) { + t.push(); + t.translate(Math.round(x), y); + t.charColor(r, g, b); + t.char(char); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + + const amount = (t.frameCount % duration) / duration; + const labelWidth = 10; + const width = Math.max(8, Math.min(24, t.grid.cols - labelWidth - 10)); + const totalWidth = labelWidth + 2 + width; + const labelX = -Math.floor(totalWidth / 2); + const left = labelX + labelWidth + 2; + + for (const curve of curves) { + const eased = t.ease(curve.name, amount); + const x = t.lerp(left, left + width, eased); + const [r, g, b] = curve.color; + + drawText(curve.name, labelX, curve.y - 1, r, g, b); + + for (let step = 0; step <= width; step++) { + plot(left + step, curve.y, '-', 70, 95, 140); + } + + plot(x, curve.y, curve.char, r, g, b); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const amount = (t.frameCount % duration) / duration; + + drawText('TEXTMODIFIER.EASE', x, y++, 100, 255, 140); + drawText('----------------------', x, y++, 80, 100, 150); + drawText('CURVES IN MOTION', x, y++, 100, 220, 255); + drawText('same amount, different timing', x, y++, 140, 160, 190); + drawText(`amount: ${amount.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipse.md b/api/textmode.js/classes/Textmodifier/methods/ellipse.md index ae828663..e77602f7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipse.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipse.md @@ -34,5 +34,58 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let rx = 0; +let ry = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + rx = 10 + Math.sin(time) * 4; + ry = 5 + Math.cos(time * 0.8) * 2; + t.push(); + t.translate(8, 1); + t.char('o'); + t.charColor(140, 220, 255); + t.cellColor(15, 25, 50); + t.ellipse(rx, ry); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ELLIPSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: OVAL PRIMITIVE', x, y++, 100, 220, 255); + drawText('Radius X and Y animate.', x, y++, 140, 160, 190); + drawText('The shape stays centered locally.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RX: ${rx.toFixed(1)}`, x, y++, 140, 255, 180); + drawText(`RY: ${ry.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md index 4af57e96..8a005333 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md @@ -37,5 +37,61 @@ Draw an ellipsoid mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.ellipsoid(8, 5, 6); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ELLIPSOID', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D ELLIPSOID', x, y++, 100, 220, 255); + drawText('Independent X, Y, Z radii.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/endShape.md b/api/textmode.js/classes/Textmodifier/methods/endShape.md index 6f9cc4ba..e822bdda 100644 --- a/api/textmode.js/classes/Textmodifier/methods/endShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/endShape.md @@ -32,5 +32,66 @@ Finish the active custom shape and enqueue its geometry. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let points = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.025; + const spikes = 7; + const outer = 16 + Math.sin(time) * 2; + const inner = 6 + Math.cos(time * 1.4) * 1.5; + points = spikes * 2; + + t.push(); + t.rotateZ(time * 18); + t.char('*'); + t.charColor(255, 220, 96); + t.cellColor(24, 16, 4); + t.lineWeight(1.4); + t.beginShape(); + for (let i = 0; i < points; i++) { + const angle = t.radians(i * (360 / points) - 90); + const radius = i % 2 === 0 ? outer : inner; + t.vertex(Math.cos(angle) * radius, Math.sin(angle) * radius); + } + t.endShape('close'); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BEGINSHAPE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM 2D POLYGON', x, y++, 100, 220, 255); + drawText('Recorded vertices form one loop.', x, y++, 140, 160, 190); + drawText('Line state is captured per vertex.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VERTICES: ${points}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md index 1ec4775b..26a010f6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md @@ -26,5 +26,97 @@ Exit pointer lock if the textmode canvas currently owns it. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let rotX = 0, + rotY = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (document.pointerLockElement === t.canvas) t.exitPointerLock(); + else t.requestPointerLock(); +}); + +t.draw(() => { + t.background(5, 8, 10); + const isLocked = document.pointerLockElement === t.canvas; + + if (isLocked) { + rotX += t.movedX * 0.35; + rotY += t.movedY * 0.35; + } else { + rotX += 0.25; + } + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const rad = Math.floor(Math.min(hw, hh) * 0.65); + const angleOffset = (rotX * 0.05) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y * 1.4); + const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; + + let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; + let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); + let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; + + if (isRing || isAxis || isTick) { + t.push(); + t.translate(x, y); + + if (isLocked) { + if (d < 3) { + t.charColor(255, 51, 51); + t.cellColor(90, 0, 0); + t.char('+'); + } else if (isTick) { + t.charColor(255, 200, 0); + t.char('#'); + } else { + t.charColor(255, 153, 0); + t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); + } + } else { + t.charColor(68, 85, 102); + t.char(isAxis ? '+' : '.'); + } + + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isLocked = document.pointerLockElement === t.canvas; + + drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); + drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); + drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); + drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); + drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/exp.md b/api/textmode.js/classes/Textmodifier/methods/exp.md index 7891ce14..68a32e09 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exp.md +++ b/api/textmode.js/classes/Textmodifier/methods/exp.md @@ -34,5 +34,68 @@ Exponential value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let input = 0; +let output = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(8, 5, 15); + input = t.norm(t.sin(t.frameCount * 0.028) + t.cos(t.frameCount * 0.018) * 0.45, -1.45, 1.45) * 3 - 1.5; + output = t.exp(input); + + for (let i = 0; i <= 36; i++) { + const xValue = t.map(i, 0, 36, -1.5, 1.5); + const y = 8 - t.exp(xValue) * 2.2; + const heat = t.norm(xValue, -1.5, 1.5); + t.push(); + t.translate(-18 + i, y); + t.char(heat > 0.7 ? '#' : '+'); + t.charColor(100 + heat * 140, 120 + heat * 90, 230); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(255, 215, 100); + t.push(); + t.translate(t.map(input, -1.5, 1.5, -18, 18), 8 - output * 2.2); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.EXP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACCELERATING GROWTH', x, y++, 100, 220, 255); + drawText('exp(x) starts quiet, then blooms.', x, y++, 140, 160, 190); + drawText('The right side lifts rapidly.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INPUT: ${input.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`EXP: ${output.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/fill.md b/api/textmode.js/classes/Textmodifier/methods/fill.md index 1de85fe5..abbeb9a6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fill.md +++ b/api/textmode.js/classes/Textmodifier/methods/fill.md @@ -30,7 +30,54 @@ Current cell color. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); + t.fill(red, 40, 120); + t.stroke(230, 245, 255); + t.char('.'); + t.rect(12, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); + drawText('Alias for cellColor.', x, y++, 140, 160, 190); + drawText('charColor controls the outline.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,7 +100,54 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); + t.fill(red, 40, 120); + t.stroke(230, 245, 255); + t.char('.'); + t.rect(12, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); + drawText('Alias for cellColor.', x, y++, 140, 160, 190); + drawText('charColor controls the outline.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -82,7 +176,54 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); + t.fill(red, 40, 120); + t.stroke(230, 245, 255); + t.char('.'); + t.rect(12, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); + drawText('Alias for cellColor.', x, y++, 140, 160, 190); + drawText('charColor controls the outline.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -104,5 +245,51 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); + t.fill(red, 40, 120); + t.stroke(230, 245, 255); + t.char('.'); + t.rect(12, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); + drawText('Alias for cellColor.', x, y++, 140, 160, 190); + drawText('charColor controls the outline.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/filter.md b/api/textmode.js/classes/Textmodifier/methods/filter.md index 1673ab3b..e1a2378d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/filter.md +++ b/api/textmode.js/classes/Textmodifier/methods/filter.md @@ -45,7 +45,51 @@ queued per frame and will be applied in order. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(16, 8); + t.filter('invert', 0.5 + 0.5 * Math.sin(t.frameCount * 0.04)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILTER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POST FILTER', x, y++, 100, 220, 255); + drawText('Applies filter to final output.', x, y++, 140, 160, 190); + drawText('Invert amount animates.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FILTER: INVERT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -78,5 +122,48 @@ queued per frame and will be applied in order. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(16, 8); + t.filter('invert', 0.5 + 0.5 * Math.sin(t.frameCount * 0.04)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FILTER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POST FILTER', x, y++, 100, 220, 255); + drawText('Applies filter to final output.', x, y++, 140, 160, 190); + drawText('Invert amount animates.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FILTER: INVERT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/flipX.md b/api/textmode.js/classes/Textmodifier/methods/flipX.md index 1279b591..e8bcff24 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipX.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipX.md @@ -34,5 +34,60 @@ Current flip state when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + for (let i = 0; i < 8; i++) { + const y = (i - 3.5) * 2; + t.push(); + t.translate(-6, y); + t.char('R'); + t.charColor(140, 220, 255); + t.point(); + t.pop(); + t.push(); + t.translate(8, y); + t.flipX(true); + t.char('R'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FLIPX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MIRROR GLYPH X', x, y++, 100, 220, 255); + drawText('Left column is normal.', x, y++, 140, 160, 190); + drawText('Right column is flipped.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FLIP X: ${t.flipX()}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/flipY.md b/api/textmode.js/classes/Textmodifier/methods/flipY.md index e88d6818..5468778d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipY.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipY.md @@ -34,5 +34,60 @@ Current flip state when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + for (let i = 0; i < 8; i++) { + const xPos = (i - 3.5) * 3; + t.push(); + t.translate(xPos, -3); + t.char('V'); + t.charColor(140, 220, 255); + t.point(); + t.pop(); + t.push(); + t.translate(xPos, 5); + t.flipY(true); + t.char('V'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FLIPY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MIRROR GLYPH Y', x, y++, 100, 220, 255); + drawText('Top row is normal.', x, y++, 140, 160, 190); + drawText('Bottom row is flipped.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FLIP Y: ${t.flipY()}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/floor.md b/api/textmode.js/classes/Textmodifier/methods/floor.md index c0037cea..a7539134 100644 --- a/api/textmode.js/classes/Textmodifier/methods/floor.md +++ b/api/textmode.js/classes/Textmodifier/methods/floor.md @@ -34,5 +34,68 @@ Largest integer less than or equal to the value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let snapped = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 8, 16); + raw = t.sin(t.frameCount * 0.035) * 11 + t.cos(t.frameCount * 0.023) * 3; + snapped = t.floor(raw); + + for (let x = -24; x <= 24; x++) { + t.char(x === snapped ? '#' : '.'); + t.charColor(x === snapped ? 255 : 55, x === snapped ? 220 : 70, 120); + t.push(); + t.translate(x, 0); + t.point(); + t.pop(); + } + + t.char('|'); + t.charColor(110, 220, 255); + t.line(snapped, -9, snapped, 9); + t.char('@'); + t.charColor(255, 140, 120); + t.push(); + t.translate(t.round(raw), -5); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FLOOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SNAP DOWN', x, y++, 100, 220, 255); + drawText('floor() chooses the lower cell.', x, y++, 140, 160, 190); + drawText('Red input becomes blue column.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`FLOOR: ${snapped}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/fontSize.md b/api/textmode.js/classes/Textmodifier/methods/fontSize.md index 7868cca1..0b4b5916 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fontSize.md +++ b/api/textmode.js/classes/Textmodifier/methods/fontSize.md @@ -34,5 +34,51 @@ Current font size when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let size = 16; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + size = t.fontSize(); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FONTSIZE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACTIVE FONT SIZE', x, y++, 100, 220, 255); + drawText('Reads the current font size.', x, y++, 140, 160, 190); + drawText('Grid derives from cell size.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); + drawText(`COLS: ${t.grid.cols}`, x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/fract.md b/api/textmode.js/classes/Textmodifier/methods/fract.md index 1eea4c8a..9f486904 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fract.md +++ b/api/textmode.js/classes/Textmodifier/methods/fract.md @@ -36,5 +36,64 @@ Fractional part in the range 0 up to, but not including, 1. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let fraction = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 17); + raw = t.frameCount * 0.035 + t.sin(t.frameCount * 0.021) * 0.5; + fraction = t.fract(raw); + + for (let x = -24; x <= 24; x++) { + const f = t.fract(raw + x * 0.18); + const y = 8 - f * 14; + t.push(); + t.translate(x, y); + t.char(f > 0.75 ? '#' : f > 0.35 ? '+' : '.'); + t.charColor(80 + f * 160, 135 + f * 100, 255); + t.point(); + t.pop(); + } + + t.char('|'); + t.charColor(255, 210, 100); + t.line(0, 8, 0, 8 - fraction * 14); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FRACT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: REPEATING DECIMALS', x, y++, 100, 220, 255); + drawText('fract(x) keeps the part after dot.', x, y++, 140, 160, 190); + drawText('The ramp resets at every integer.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`FRACT: ${fraction.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/frameRate.md b/api/textmode.js/classes/Textmodifier/methods/frameRate.md index a447a38f..2c3b202d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/frameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/frameRate.md @@ -32,5 +32,60 @@ Set the target frame rate, or get the current measured frame rate when called wi ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let measured = 0; +let target = 60; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + target = Math.floor(t.frameCount / 180) % 2 === 0 ? 60 : 30; + t.frameRate(target); + measured = t.frameRate(); + const bars = Math.round(measured / 5); + for (let i = 0; i < bars; i++) { + t.push(); + t.translate(-18 + i, 3); + t.char('|'); + t.charColor(120, 220, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.FRAMERATE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FPS CONTROL', x, y++, 100, 220, 255); + drawText('Target alternates 60 and 30.', x, y++, 140, 160, 190); + drawText('Bars show measured rate.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TARGET: ${target}`, x, y++, 140, 255, 180); + drawText(`FPS: ${measured.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepad.md b/api/textmode.js/classes/Textmodifier/methods/gamepad.md index a84368c2..0e006841 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepad.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepad.md @@ -37,5 +37,56 @@ Returns `undefined` when that slot is currently absent or disconnected. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPAD', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const pad = t.gamepad(0); + const state = pad ? 'FOUND' : 'EMPTY'; + drawText(`SLOT 0: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md index 66dcf101..08f7bc9f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md @@ -36,5 +36,61 @@ simpler choice; use this callback when you specifically want change notification ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let lastAxis = 'waiting'; + +t.gamepadAxisChanged((data) => { + const name = data.standardAxisName || 'axis ' + data.axisIndex; + lastAxis = name + ' ' + data.value.toFixed(2); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADAXISCHANGED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`AXIS: ${lastAxis}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md index dae1ece1..784757c5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md @@ -34,5 +34,60 @@ This is a legacy-style single-callback shortcut for the `'gamepadButtonPressed'` ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let lastPress = 'waiting'; + +t.gamepadButtonPressed((data) => { + lastPress = data.standardButtonName || 'button ' + data.buttonIndex; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADBUTTONPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`PRESS: ${lastPress}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md index 61340f85..19048fa0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md @@ -34,5 +34,60 @@ This is a legacy-style single-callback shortcut for the `'gamepadButtonReleased' ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let lastRelease = 'waiting'; + +t.gamepadButtonReleased((data) => { + lastRelease = data.standardButtonName || 'button ' + data.buttonIndex; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADBUTTONRELEASED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RELEASE: ${lastRelease}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md index d9465031..72bbb62f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md @@ -36,5 +36,60 @@ leaving any listeners added via [Textmodifier.on](on.md) untouched. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let lastConnect = 'waiting'; + +t.gamepadConnected((data) => { + lastConnect = 'slot ' + data.gamepad.index; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADCONNECTED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CONNECT: ${lastConnect}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md index b5039810..4517d5bb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md @@ -34,5 +34,60 @@ This is a legacy-style single-callback shortcut for the `'gamepadDisconnected'` ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let lastDisconnect = 'waiting'; + +t.gamepadDisconnected((data) => { + lastDisconnect = 'slot ' + data.gamepad.index; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADDISCONNECTED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DISCON: ${lastDisconnect}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/image.md b/api/textmode.js/classes/Textmodifier/methods/image.md index b28dac43..f8b3fa30 100644 --- a/api/textmode.js/classes/Textmodifier/methods/image.md +++ b/api/textmode.js/classes/Textmodifier/methods/image.md @@ -37,5 +37,55 @@ Draw a framebuffer, image, video, or texture source to the currently bound frame ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const fb = t.createFramebuffer({ width: 24, height: 14 }); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + fb.begin(); + t.clear(); + t.background(20, 30, 60); + t.rotateZ(t.frameCount * 2); + t.char('#'); + t.charColor(255, 210, 120); + t.rect(12, 4); + fb.end(); + t.image(fb, 24, 14); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.IMAGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DRAW IMAGE SOURCE', x, y++, 100, 220, 255); + drawText('Framebuffer is drawn as image.', x, y++, 140, 160, 190); + drawText('Offscreen content rotates.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('SOURCE: FRAMEBUFFER', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md index e9d0812d..23a9f3e6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md +++ b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md @@ -40,5 +40,70 @@ When called without arguments, returns the current input grid mode:
## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const inputLayer = t.layers.add(); +let locked = false; +let mode = 'topmost'; + +t.setup(() => { + inputLayer.grid.cols = 24; + inputLayer.grid.rows = 12; +}); + +t.mouseClicked(() => { + locked = !locked; + t.inputGrid(locked ? inputLayer.grid : 'topmost'); + mode = locked ? 'locked' : 'topmost'; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.charColor(60, 80, 120); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); +}); + +inputLayer.draw(() => { + t.clear(); + t.charColor(100, 220, 255); + t.char('+'); + t.rect(inputLayer.grid.cols, inputLayer.grid.rows); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.INPUTGRID', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INPUT GRID LOCK', x, y++, 100, 220, 255); + drawText('Mouse mapping can lock.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${mode}`, x, y++, 140, 255, 180); + drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/invert.md b/api/textmode.js/classes/Textmodifier/methods/invert.md index 82834b33..de42038b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/invert.md +++ b/api/textmode.js/classes/Textmodifier/methods/invert.md @@ -34,5 +34,64 @@ Current inversion state when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(10, 12, 24); + + const count = 15; + for (let i = 0; i < count; i++) { + t.push(); + t.translate((i - (count - 1) / 2) * 5, 0); + + const shouldInvert = (i + Math.floor(t.frameCount / 25)) % 2 === 0; + t.invert(shouldInvert); + + t.charColor(255, 100, 100); + t.cellColor(0, 50, 100); + t.char('█'); + t.rect(4, 18); + t.pop(); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const invertActive = Math.floor(t.frameCount / 25) % 2 === 0; + + drawText('TEXTMODIFIER.INVERT', x, y++, 255, 100, 100); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CHROMA CHANNEL INVERSION', x, y++, 100, 220, 255); + drawText('Swaps char and cell colors.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = invertActive ? 'INVERTED' : 'STANDARD'; + drawText(`INVERT: ${state}`, x, y++, 120, 205, 255); + drawText('RECTS: 15', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('t.invert(shouldInvert)', x, y++, 100, 220, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md index 5540a46b..7d8878a1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md @@ -34,5 +34,101 @@ Check whether a key is currently pressed. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(), + flames = []; +let px = 0, + py = 0, + vx = 0, + vy = 0, + active = false; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 20); + const up = t.isKeyPressed('ArrowUp') || t.isKeyPressed('w') || t.isKeyPressed('W'); + const down = t.isKeyPressed('ArrowDown') || t.isKeyPressed('s') || t.isKeyPressed('S'); + const left = t.isKeyPressed('ArrowLeft') || t.isKeyPressed('a') || t.isKeyPressed('A'); + const right = t.isKeyPressed('ArrowRight') || t.isKeyPressed('d') || t.isKeyPressed('D'); + const boost = t.isKeyPressed(' '); + active = up || down || left || right || boost; + + if (up) vy -= 0.2; + if (down) vy += 0.2; + if (left) vx -= 0.2; + if (right) vx += 0.2; + if (boost) { + vx *= 1.05; + vy *= 1.05; + } + + if (active) flames.unshift({ x: px, y: py, vx: -vx * 0.5, vy: -vy * 0.5, life: 1 }); + if (flames.length > 40) flames.length = 40; + + vx *= 0.91; + vy *= 0.91; + px += vx; + py += vy; + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + px = Math.max(-hw + 5, Math.min(hw - 5, px)); + py = Math.max(-hh + 5, Math.min(hh - 5, py)); + + for (let i = flames.length - 1; i >= 0; i--) { + const f = flames[i]; + f.x += f.vx; + f.y += f.vy; + if ((f.life -= 0.04) <= 0) { + flames.splice(i, 1); + continue; + } + const fx = Math.round(f.x), + fy = Math.round(f.y); + if (fx >= -hw && fx <= hw && fy >= -hh && fy <= hh) { + t.push(); + t.translate(fx, fy); + t.charColor(255, f.life > 0.5 ? 170 : 80, 0); + if (f.life > 0.6) t.cellColor(90, 30, 0); + t.char(f.life > 0.7 ? '█' : f.life > 0.4 ? '▓' : '░'); + t.point(); + t.pop(); + } + } + + t.push(); + t.translate(Math.round(px), Math.round(py)); + t.charColor(0, boost ? 255 : 170, 255); + t.cellColor(0, 50, 90); + t.char(up ? '▲' : down ? '▼' : left ? '◄' : right ? '►' : '♦'); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.ISKEYPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SYNCHRONOUS KEY HOLD', x, y++, 100, 220, 255); + drawText('Evaluates held key state every frame.', x, y++, 140, 160, 190); + drawText('Use Arrows / WASD / Space to thrust.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('THRUSTERS: ' + (active ? 'ENGAGED' : 'IDLE'), x, y++, 140, 255, 180); + drawText('SPEED: ' + Math.hypot(vx, vy).toFixed(2), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/isLooping.md b/api/textmode.js/classes/Textmodifier/methods/isLooping.md index 7584d000..4f20539f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isLooping.md +++ b/api/textmode.js/classes/Textmodifier/methods/isLooping.md @@ -28,5 +28,59 @@ Whether the automatic render loop is currently running. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.mousePressed(() => { + if (t.isLooping()) { + t.noLoop(); + t.redraw(); + } else { + t.loop(); + } +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char(t.isLooping() ? '>' : '|'); + t.charColor(t.isLooping() ? 100 : 255, 255, 140); + t.rotateZ(t.frameCount * 5); + t.rect(10, 10); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.ISLOOPING', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOOP STATE', x, y++, 100, 220, 255); + drawText('Compact API demonstration.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = t.isLooping() ? 'TRUE' : 'FALSE'; + drawText(`LOOPING: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md index 6d7d838b..7d423f9e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md @@ -32,5 +32,99 @@ Register the single-callback handler for key press events. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(), + rings = [], + bars = new Array(10).fill(0); +let keyCount = 0, + lastKey = 'NONE'; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.keyPressed((data) => { + keyCount++; + const k = data.key || 'KEY'; + lastKey = k; + rings.unshift({ age: 0, maxAge: 45, char: k.length === 1 ? k : '+' }); + bars[(k.length > 0 ? k.charCodeAt(0) : 0) % 10] = 1.0; + if (rings.length > 10) rings.length = 10; +}); + +t.draw(() => { + t.background(10, 5, 24); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + for (let i = rings.length - 1; i >= 0; i--) { + if (++rings[i].age >= rings[i].maxAge) rings.splice(i, 1); + } + + for (let i = 0; i < 10; i++) { + bars[i] *= 0.94; + const h = Math.floor(bars[i] * 12), + bx = (i - 4.5) * 4; + for (let dy = 0; dy < h; dy++) { + t.push(); + t.translate(Math.round(bx), hh - 4 - dy); + t.charColor(255, Math.floor(100 + dy * 12), Math.floor(dy * 20)); + if (dy > 8) t.cellColor(90, 0, 50); + t.char(dy === h - 1 ? '=' : '#'); + t.point(); + t.pop(); + } + } + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y); + let ringIntensity = 0, + ringChar = '+'; + for (let i = 0; i < rings.length; i++) { + const r = rings[i], + rad = r.age * 0.9, + dist = Math.abs(d - rad); + if (dist < 2.0) { + ringIntensity += (1 - dist / 2.0) * (1 - r.age / r.maxAge); + if (r.char.length === 1) ringChar = r.char; + } + } + if (ringIntensity > 0.15) { + t.push(); + t.translate(x, y); + t.charColor(0, 240, 255); + if (ringIntensity > 0.4) t.cellColor(0, 60, 90); + t.char(ringChar); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.KEYPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INITIAL KEY DOWN EVENT', x, y++, 100, 220, 255); + drawText('Fires on initial key down-stroke.', x, y++, 140, 160, 190); + drawText('Keypress ejects frequency shockwave.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('KEY PRESSES: ' + keyCount, x, y++, 140, 255, 180); + drawText('LAST KEY DOWN: ' + lastKey, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md index 8494a452..fc45b74c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md @@ -32,5 +32,98 @@ Register the single-callback handler for key release events. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(), + cascades = []; +let releaseCount = 0, + lastReleased = 'NONE'; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.keyReleased((data) => { + releaseCount++; + const k = data.key || 'KEY'; + lastReleased = k; + const ch = k.length === 1 ? k : '♦'; + + for (let i = 0; i < 18; i++) { + const a = (i / 18) * Math.PI * 2 + (Math.random() - 0.5) * 0.2; + const s = 0.5 + Math.random() * 1.1; + cascades.unshift({ x: 0, y: 0, vx: Math.cos(a) * s, vy: Math.sin(a) * s, life: 1.0, char: ch }); + } + if (cascades.length > 90) cascades.length = 90; +}); + +t.draw(() => { + t.background(6, 8, 16); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + // Central energy crystal + const tm = t.frameCount * 0.04; + const pulse = (Math.sin(tm) + 1) * 0.5; + t.push(); + t.translate(0, 0); + t.charColor(0, Math.floor(180 + pulse * 75), 255); + t.cellColor(0, 40, 80); + t.char('♦'); + t.point(); + t.pop(); + + // Dissipation particle cascades + for (let i = cascades.length - 1; i >= 0; i--) { + const c = cascades[i]; + c.x += c.vx; + c.y += c.vy; + c.vx *= 0.94; + c.vy *= 0.94; + if ((c.life -= 0.02) <= 0) { + cascades.splice(i, 1); + continue; + } + + const cx = Math.round(c.x), + cy = Math.round(c.y); + if (cx >= -hw && cx <= hw && cy >= -hh && cy <= hh) { + t.push(); + t.translate(cx, cy); + if (c.life > 0.6) { + t.charColor(255, 204, 0); + t.cellColor(70, 50, 0); + } else { + t.charColor(0, Math.floor(100 + c.life * 155), 200); + } + t.char(c.life > 0.7 ? c.char : c.life > 0.4 ? '∙' : '·'); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.KEYRELEASED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: UP-STROKE RELEASE CASCADE', x, y++, 100, 220, 255); + drawText('Fires on key release up-stroke.', x, y++, 140, 160, 190); + drawText('Key release dissipates energy cascades.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('KEY RELEASES: ' + releaseCount, x, y++, 140, 255, 180); + drawText('LAST RELEASED: ' + lastReleased, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md index dfff2b7b..e8939557 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md @@ -35,5 +35,93 @@ punctuation, and space. It does not fire for modifier keys or control-key chords ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let buffer = 'TEXTMODE.JS', + typedCount = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +function getCardChar(cx, cy, w, h) { + if ((cy === 0 || cy === h - 1) && (cx === 0 || cx === w - 1)) return '+'; + return cy === 0 || cy === h - 1 ? '-' : '|'; +} + +t.keyTyped((data) => { + if (data.key && data.key.length === 1) { + typedCount++; + buffer = (buffer + data.key).slice(-28); + } +}); + +t.draw(() => { + t.background(4, 16, 8); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2), + tm = t.frameCount * 0.05; + + for (let y = -hh; y <= hh; y += 2) { + for (let x = -hw; x <= hw; x += 2) { + const rain = (Math.sin(x * 0.2 + tm + y * 0.1) + 1) * 0.5; + if (rain > 0.65) { + t.push(); + t.translate(x, y); + t.charColor(10, Math.floor(40 + rain * 60), 20); + t.char(String.fromCharCode(65 + ((x + y + Math.floor(tm)) % 26))); + t.point(); + t.pop(); + } + } + } + + const cardW = 32, + cardH = 5, + startX = -16, + startY = -2; + for (let cy = 0; cy < cardH; cy++) { + for (let cx = 0; cx < cardW; cx++) { + const isEdge = cx === 0 || cx === cardW - 1 || cy === 0 || cy === cardH - 1; + t.push(); + t.translate(startX + cx, startY + cy); + t.cellColor(2, 24, 12); + t.charColor(0, 180, 80); + t.char(isEdge ? getCardChar(cx, cy, cardW, cardH) : ' '); + t.point(); + t.pop(); + } + } + + t.push(); + t.printAlign('center', 'middle'); + t.charColor(0, 255, 102); + t.print(buffer + (Math.floor(t.frameCount / 20) % 2 === 0 ? '_' : ' '), 0, 0); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.KEYTYPED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PRINTABLE INPUT BUFFER', x, y++, 100, 220, 255); + drawText('Captures printable typed characters.', x, y++, 140, 160, 190); + drawText('Type any key to append to stream.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('TYPED CHARACTERS: ' + typedCount, x, y++, 140, 255, 180); + drawText('BUFFER LENGTH: ' + buffer.length, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lerp.md b/api/textmode.js/classes/Textmodifier/methods/lerp.md index 7809aa9b..7b73c84c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lerp.md +++ b/api/textmode.js/classes/Textmodifier/methods/lerp.md @@ -39,5 +39,84 @@ The interpolated value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let blend = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(9, 10, 18); + blend = (Math.sin(t.frameCount * 0.035) + 1) * 0.5; + const left = -16; + const right = 16; + + t.char('-'); + t.charColor(55, 75, 115); + t.line(left, 0, right, 0); + + for (let i = 0; i <= 12; i++) { + const local = i / 12; + const x = t.lerp(left, right, local); + const y = Math.sin(local * Math.PI * 2 + t.frameCount * 0.04) * 5; + const r = Math.round(t.lerp(90, 255, local)); + const b = Math.round(t.lerp(255, 80, local)); + t.char(i % 2 === 0 ? '+' : '.'); + t.charColor(r, 160, b); + drawPoint(x, y); + } + + const x = t.lerp(left, right, blend); + const y = t.lerp(-7, 7, blend); + const size = Math.round(t.lerp(1, 4, blend)); + t.char('#'); + t.charColor(t.lerp(90, 255, blend), 230, t.lerp(255, 90, blend)); + t.rect(size, size); + + t.push(); + t.translate(x, y); + t.char('@'); + t.charColor(120, 255, 190); + t.rect(size + 1, size + 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LERP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INTERPOLATION', x, y++, 100, 220, 255); + drawText('lerp(a,b,t) blends between values.', x, y++, 140, 160, 190); + drawText('Position, color, and size all blend.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`T: ${blend.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md index 44c55f0a..27021fef 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md +++ b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md @@ -40,5 +40,56 @@ Negative inputs are clamped to `0`. If all inputs resolve to `0`, the falloff re ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + value = 0.5 + 0.5 * Math.sin(time); + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + t.lightFalloff(1, value * 0.08, value * 0.01); + t.pointLight([255, 210, 120], { x: 18, y: -18, z: 28 }); + t.rotateY(time * 40); + t.char('#'); + t.charColor(140, 220, 255); + t.sphere(7); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LIGHTFALLOFF', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LIGHT FALLOFF', x, y++, 100, 220, 255); + drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); + drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FALLOFF: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/line.md b/api/textmode.js/classes/Textmodifier/methods/line.md index 555121b9..c4e9529f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/line.md +++ b/api/textmode.js/classes/Textmodifier/methods/line.md @@ -39,5 +39,60 @@ Draw a line from `(x1, y1)` to `(x2, y2)`. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let a = 0; +let b = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.025; + a = Math.sin(time) * 10; + b = Math.cos(time * 0.7) * 7; + t.charColor(60, 70, 100); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + t.charColor(120, 220, 255); + t.char('#'); + t.line(-18, -b, 18, b); + t.charColor(255, 210, 120); + t.line(-a, -10, a, 10); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DRAW SEGMENTS', x, y++, 100, 220, 255); + drawText('Connects two grid coordinates.', x, y++, 140, 160, 190); + drawText('Animated endpoints cross center.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`A: ${a.toFixed(1)}`, x, y++, 140, 255, 180); + drawText(`B: ${b.toFixed(1)}`, x, y++, 255, 210, 120); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md index d101c55a..83e2a84c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md +++ b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md @@ -34,5 +34,56 @@ Current line weight when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let weight = 1; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + weight = 1 + Math.floor((t.frameCount / 60) % 4); + t.charColor(70, 80, 110); + t.char('.'); + t.line(-20, -6, 20, -6); + t.line(-20, 6, 20, 6); + t.lineWeight(weight); + t.charColor(120, 255, 180); + t.char('#'); + t.line(-20, 0, 20, 0); + t.lineWeight(1); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINEWEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LINE THICKNESS', x, y++, 100, 220, 255); + drawText('Controls line cell thickness.', x, y++, 140, 160, 190); + drawText('Weight resets after the demo line.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`WEIGHT: ${weight}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loadFont.md b/api/textmode.js/classes/Textmodifier/methods/loadFont.md index 4e592edf..946af3ec 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadFont.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadFont.md @@ -44,5 +44,89 @@ The loaded TextmodeFont. ## Example - +```javascript +const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const accentLayer = t.layers.add({ fontSize: 16, blendMode: 'additive' }); +const labelLayer = t.layers.add(); + +let baseFont = null; +let reusableFont = null; +let loaded = false; + +t.setup(async () => { + baseFont = await t.loadFont(BESCII_URL); + reusableFont = await t.loadFont(BESCII_URL, false); + await accentLayer.loadFont(reusableFont); + loaded = true; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawGlyphStrip(font, y, r, g, b) { + const glyphs = font.characters; + const count = Math.min(glyphs.length, Math.max(8, Math.floor(t.grid.cols * 0.55))); + const start = Math.floor((t.frameCount / 8) % glyphs.length); + const x = -Math.floor(count / 2); + for (let i = 0; i < count; i++) { + const glyph = glyphs[(start + i) % glyphs.length]; + t.push(); + t.translate(x + i, y); + t.char(glyph.character); + t.charColor(r, g, b); + t.point(); + t.pop(); + } +} + +t.draw(() => { + t.background(5, 8, 18); + if (!loaded) return; + + drawGlyphStrip(baseFont, -2, 255, 235, 120); + drawText('ACTIVE BASE FONT', -8, -5, 255, 235, 120); +}); + +accentLayer.draw(() => { + t.clear(); + if (!loaded) return; + + drawGlyphStrip(reusableFont, 4, 120, 220, 255); + drawText('REUSED ON LAYER', -7, 7, 120, 220, 255); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.LOADFONT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOAD WEB FONT', x, y++, 100, 220, 255); + drawText('true activates the base layer.', x, y++, 140, 160, 190); + drawText('false returns a reusable font.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = loaded ? 'READY' : 'LOADING'; + drawText(`FONT: ${state}`, x, y++, 140, 255, 180); + if (loaded) drawText(`GLYPHS: ${baseFont.characters.length}`, x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loadImage.md b/api/textmode.js/classes/Textmodifier/methods/loadImage.md index e61f5293..e6bdba88 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadImage.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadImage.md @@ -34,5 +34,52 @@ The loaded TextmodeImage. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + source = await t.loadImage('https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&q=80'); + source.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(0); + if (source) t.image(source, t.grid.cols, t.grid.rows); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOADIMAGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOAD IMAGE', x, y++, 100, 220, 255); + drawText('Loads media for this example.', x, y++, 140, 160, 190); + drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(source ? 'IMAGE: READY' : 'IMAGE: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md index 5bf3e163..a141f72c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md @@ -44,5 +44,65 @@ The loaded TextmodeTileset. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + source = await t.loadTileset({ + source: 'https://littlebitspace.com/resources/fonts/T64.png', + columns: 16, + rows: 16, + count: 256, + }); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (source) { + for (let i = 0; i < 64; i++) { + t.push(); + t.translate((i % 16) - 8, Math.floor(i / 16)); + t.char(i); + t.charColor(120, 220, 255); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOADTILESET', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOAD TILESET', x, y++, 100, 220, 255); + drawText('Loads media for this example.', x, y++, 140, 160, 190); + drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(source ? 'TILESET: READY' : 'TILESET: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md index c37064d3..78bdcf96 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md @@ -32,5 +32,52 @@ Load a video source that can be drawn with [image](image.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + source = await t.loadVideo('https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'); + source.play(); +}); + +t.draw(() => { + t.background(0); + if (source) t.image(source, t.grid.cols, t.grid.rows); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOADVIDEO', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOAD VIDEO', x, y++, 100, 220, 255); + drawText('Loads media for this example.', x, y++, 140, 160, 190); + drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(source ? 'VIDEO: READY' : 'VIDEO: WAIT', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/log.md b/api/textmode.js/classes/Textmodifier/methods/log.md index 8aceb499..1c8cfbac 100644 --- a/api/textmode.js/classes/Textmodifier/methods/log.md +++ b/api/textmode.js/classes/Textmodifier/methods/log.md @@ -34,5 +34,68 @@ Natural logarithm. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let input = 1; +let output = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 8, 16); + input = 1 + t.norm(t.sin(t.frameCount * 0.03) + t.cos(t.frameCount * 0.019) * 0.4, -1.4, 1.4) * 24; + output = t.log(input); + + for (let i = 1; i <= 36; i++) { + const value = 1 + i * 0.7; + const y = 8 - t.log(value) * 4; + const glow = t.norm(value, 1, 26); + t.push(); + t.translate(-18 + i, y); + t.char(glow > 0.7 ? '#' : '+'); + t.charColor(90 + glow * 140, 155 + glow * 80, 255); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(255, 215, 100); + t.push(); + t.translate(t.map(input, 1, 26, -17, 18), 8 - output * 4); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOG', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: COMPRESSING GROWTH', x, y++, 100, 220, 255); + drawText('log(x) rises fast, then settles.', x, y++, 140, 160, 190); + drawText('Wide inputs fit a gentle curve.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INPUT: ${input.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`LOG: ${output.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/longPress.md b/api/textmode.js/classes/Textmodifier/methods/longPress.md index 7c2b8b6c..45c7cd82 100644 --- a/api/textmode.js/classes/Textmodifier/methods/longPress.md +++ b/api/textmode.js/classes/Textmodifier/methods/longPress.md @@ -35,5 +35,76 @@ configured tolerance. The event includes the press duration in milliseconds. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.longPress((data) => { + const touch = data?.touch || t.mouse; + addPulse('LONG', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LONGPRESS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LONG PRESS', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('LONG: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lookAt.md b/api/textmode.js/classes/Textmodifier/methods/lookAt.md index 8c5cfcbc..e9cac45a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lookAt.md +++ b/api/textmode.js/classes/Textmodifier/methods/lookAt.md @@ -43,5 +43,62 @@ Update the look-at target and optional up vector for the active camera. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let targetX = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.03; + targetX = Math.sin(time) * 10; + t.perspective(58, 0.1, 4096); + t.camera(0, 0, 44); + t.lookAt(targetX, 0, 0); + t.ambientLight(20, 24, 34); + t.pointLight([255, 210, 140], { x: 16, y: -16, z: 28 }); + t.push(); + t.translate(targetX, 0, 0); + t.char('*'); + t.charColor(255, 220, 120); + t.box(4, 4, 4); + t.pop(); + t.char('#'); + t.charColor(120, 220, 255); + t.box(8, 8, 8); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOOKAT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: AIM CAMERA', x, y++, 100, 220, 255); + drawText('Camera eye remains fixed.', x, y++, 140, 160, 190); + drawText('Target slides across X.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TARGET X: ${targetX.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loop.md b/api/textmode.js/classes/Textmodifier/methods/loop.md index 7306e74d..9366f27e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loop.md +++ b/api/textmode.js/classes/Textmodifier/methods/loop.md @@ -26,5 +26,52 @@ Resume the rendering loop if it was stopped by [noLoop](noLoop.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mousePressed(() => { + t.loop(); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.rotateZ(t.frameCount * 3); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(10, 2); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LOOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESUME DRAW LOOP', x, y++, 100, 220, 255); + drawText('Click calls loop().', x, y++, 140, 160, 190); + drawText('Spinner shows active frames.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CLICK: LOOP', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/map.md b/api/textmode.js/classes/Textmodifier/methods/map.md index 38136438..2f20e664 100644 --- a/api/textmode.js/classes/Textmodifier/methods/map.md +++ b/api/textmode.js/classes/Textmodifier/methods/map.md @@ -43,5 +43,69 @@ The remapped value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let mappedHeight = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 17); + const halfCols = Math.max(1, Math.floor(t.grid.cols / 2)); + const halfRows = Math.max(1, Math.floor(t.grid.rows / 2)); + const pointer = t.constrain(t.mouse.x, -halfCols, halfCols); + mappedHeight = t.map(pointer, -halfCols, halfCols, 1, 13); + + for (let i = 0; i < 17; i++) { + const x = -16 + i * 2; + const wave = Math.sin(t.frameCount * 0.04 + i * 0.55); + const height = Math.round(t.map(wave, -1, 1, 1, mappedHeight)); + const red = Math.round(t.map(i, 0, 16, 80, 255)); + const blue = Math.round(t.map(height, 1, 13, 255, 90)); + + t.char(i % 3 === 0 ? '#' : '|'); + t.charColor(red, 190, blue); + t.push(); + t.translate(x, 7 - height / 2); + t.rect(1, height); + t.pop(); + } + + const y = t.map(t.mouse.y, -halfRows, halfRows, -7, 7); + t.char('-'); + t.charColor(255, 230, 120); + t.line(-18, y, 18, y); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MAP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RANGE REMAPPING', x, y++, 100, 220, 255); + drawText('Mouse grid values become bar ranges.', x, y++, 140, 160, 190); + drawText('map() also colors each column.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`HEIGHT: ${mappedHeight.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/max.md b/api/textmode.js/classes/Textmodifier/methods/max.md index f1b38436..989fd92a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/max.md +++ b/api/textmode.js/classes/Textmodifier/methods/max.md @@ -36,7 +36,68 @@ Largest value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let high = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 6, 17); + const values = []; + for (let i = 0; i < 15; i++) { + values.push(t.round(t.cos(t.frameCount * 0.032 + i * 0.62) * 7 + t.sin(i * 0.8) * 3)); + } + high = t.max(values); + + for (let i = 0; i < values.length; i++) { + const x = -21 + i * 3; + const isHigh = values[i] === high; + t.push(); + t.translate(x, 6 - values[i] / 2); + t.char(isHigh ? '@' : '#'); + t.charColor(isHigh ? 120 : 80, isHigh ? 255 : 140, isHigh ? 170 : 230); + t.rect(1, t.abs(values[i]) + 1); + t.pop(); + } + + t.char('-'); + t.charColor(120, 245, 180); + t.line(-23, 6 - high, 23, 6 - high); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MAX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: UPPER ENVELOPE', x, y++, 100, 220, 255); + drawText('max(values...) finds the peak.', x, y++, 140, 160, 190); + drawText('The green line rides the crest.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MAX: ${high}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -60,5 +121,65 @@ Largest value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let high = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 6, 17); + const values = []; + for (let i = 0; i < 15; i++) { + values.push(t.round(t.cos(t.frameCount * 0.032 + i * 0.62) * 7 + t.sin(i * 0.8) * 3)); + } + high = t.max(values); + + for (let i = 0; i < values.length; i++) { + const x = -21 + i * 3; + const isHigh = values[i] === high; + t.push(); + t.translate(x, 6 - values[i] / 2); + t.char(isHigh ? '@' : '#'); + t.charColor(isHigh ? 120 : 80, isHigh ? 255 : 140, isHigh ? 170 : 230); + t.rect(1, t.abs(values[i]) + 1); + t.pop(); + } + + t.char('-'); + t.charColor(120, 245, 180); + t.line(-23, 6 - high, 23, 6 - high); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MAX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: UPPER ENVELOPE', x, y++, 100, 220, 255); + drawText('max(values...) finds the peak.', x, y++, 140, 160, 190); + drawText('The green line rides the crest.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MAX: ${high}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/min.md b/api/textmode.js/classes/Textmodifier/methods/min.md index c31bae0e..19bd43ff 100644 --- a/api/textmode.js/classes/Textmodifier/methods/min.md +++ b/api/textmode.js/classes/Textmodifier/methods/min.md @@ -36,7 +36,68 @@ Smallest value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let low = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 8, 17); + const values = []; + for (let i = 0; i < 15; i++) { + values.push(t.round(t.sin(t.frameCount * 0.035 + i * 0.7) * 7 + t.cos(i) * 3)); + } + low = t.min(values); + + for (let i = 0; i < values.length; i++) { + const x = -21 + i * 3; + const isLow = values[i] === low; + t.push(); + t.translate(x, 6 - values[i] / 2); + t.char(isLow ? '@' : '#'); + t.charColor(isLow ? 255 : 80, isLow ? 215 : 140, isLow ? 110 : 230); + t.rect(1, t.abs(values[i]) + 1); + t.pop(); + } + + t.char('-'); + t.charColor(255, 160, 110); + t.line(-23, 6 - low, 23, 6 - low); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MIN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOWER ENVELOPE', x, y++, 100, 220, 255); + drawText('min(array) finds the lowest bar.', x, y++, 140, 160, 190); + drawText('The orange line follows it.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MIN: ${low}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -60,5 +121,65 @@ Smallest value. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let low = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 8, 17); + const values = []; + for (let i = 0; i < 15; i++) { + values.push(t.round(t.sin(t.frameCount * 0.035 + i * 0.7) * 7 + t.cos(i) * 3)); + } + low = t.min(values); + + for (let i = 0; i < values.length; i++) { + const x = -21 + i * 3; + const isLow = values[i] === low; + t.push(); + t.translate(x, 6 - values[i] / 2); + t.char(isLow ? '@' : '#'); + t.charColor(isLow ? 255 : 80, isLow ? 215 : 140, isLow ? 110 : 230); + t.rect(1, t.abs(values[i]) + 1); + t.pop(); + } + + t.char('-'); + t.charColor(255, 160, 110); + t.line(-23, 6 - low, 23, 6 - low); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MIN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOWER ENVELOPE', x, y++, 100, 220, 255); + drawText('min(array) finds the lowest bar.', x, y++, 140, 160, 190); + drawText('The orange line follows it.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MIN: ${low}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md index 05bb98ff..e0c51dac 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md @@ -32,5 +32,87 @@ Register the single-callback handler for mouse clicks. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const RAMP = ' .:=+*#%@'; +const labelLayer = t.layers.add(); +const ripples = []; +let clickCount = 0; +let lastPos = 'NONE'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (t.mouse.x !== Number.NEGATIVE_INFINITY) { + clickCount++; + lastPos = `(${t.mouse.x}, ${t.mouse.y})`; + ripples.unshift({ x: t.mouse.x, y: t.mouse.y, age: 0, maxAge: 60 }); + if (ripples.length > 12) ripples.length = 12; + } +}); + +t.draw(() => { + t.background(10, 8, 24); + for (let i = ripples.length - 1; i >= 0; i--) { + if (++ripples[i].age >= ripples[i].maxAge) ripples.splice(i, 1); + } + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2), + tm = t.frameCount * 0.04; + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const ambient = (Math.sin(x * 0.15 + tm) * Math.cos(y * 0.15 - tm * 0.8) + 1) * 0.2; + let rippleVal = 0; + for (let i = 0; i < ripples.length; i++) { + const rip = ripples[i], + d = Math.hypot(x - rip.x, y - rip.y), + rad = rip.age * 0.75; + const dist = Math.abs(d - rad); + if (dist < 3.5) rippleVal += Math.cos((dist / 3.5) * Math.PI * 0.5) * (1 - rip.age / rip.maxAge); + } + const val = Math.min(1, ambient + rippleVal); + if (val > 0.08) { + const charIdx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); + t.push(); + t.translate(x, y); + if (rippleVal > 0.3) { + const g = Math.min(1, (rippleVal - 0.3) / 0.7); + t.charColor(Math.floor(220 + g * 35), Math.floor(170 + g * 85), Math.floor(51 + g * 204)); + t.cellColor(Math.floor(40 * g), Math.floor(20 * g), Math.floor(60 * g)); + } else { + const b = val / 0.5; + t.charColor(Math.floor(26 + b * 20), Math.floor(58 + b * 50), Math.floor(75 + b * 60)); + } + t.char(RAMP[charIdx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSECLICKED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISCRETE CLICK EVENT', x, y++, 100, 220, 255); + drawText('Fires once per press & release.', x, y++, 140, 160, 190); + drawText('Clicking injects wave discharge.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('TOTAL CLICKS: ' + clickCount, x, y++, 140, 255, 180); + drawText('LAST CLICK: ' + lastPos, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md index ec234e6d..189def06 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md @@ -32,5 +32,94 @@ Register the single-callback handler for mouse dragging. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +const particles = []; +let dragCount = 0; +let isDragging = false; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseDragged(() => { + if (t.mouse.x === Number.NEGATIVE_INFINITY) return; + isDragging = true; + dragCount++; + const vx = (t.mouse.x - t.pmouse.x) * 0.3; + const vy = (t.mouse.y - t.pmouse.y) * 0.3; + particles.unshift({ x: t.mouse.x, y: t.mouse.y, vx, vy, life: 1 }); + if (particles.length > 80) particles.length = 80; +}); + +t.draw(() => { + t.background(8, 12, 20); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.02; + + for (let y = -hh; y <= hh; y += 3) { + for (let x = -hw; x <= hw; x += 3) { + const a = Math.sin(x * 0.08 + tm) + Math.cos(y * 0.08 - tm * 0.8); + t.push(); + t.translate(x, y); + t.charColor(14, 56, 43); + t.char(a > 1.0 ? '/' : a > 0.2 ? '|' : a > -0.8 ? '\\' : '-'); + t.point(); + t.pop(); + } + } + + for (let i = particles.length - 1; i >= 0; i--) { + const p = particles[i]; + p.x += p.vx; + p.y += p.vy; + p.vx *= 0.94; + p.vy *= 0.94; + const a = Math.sin(p.x * 0.08 + tm) + Math.cos(p.y * 0.08 - tm * 0.8); + p.vx += Math.cos(a) * 0.05; + p.vy += Math.sin(a) * 0.05; + if ((p.life -= 0.02) <= 0) { + particles.splice(i, 1); + continue; + } + const px = Math.round(p.x); + const py = Math.round(p.y); + if (px >= -hw && px <= hw && py >= -hh && py <= hh) { + t.push(); + t.translate(px, py); + t.charColor(p.life > 0.6 ? 163 : 57, p.life > 0.6 ? 255 : p.life > 0.3 ? 255 : 90, p.life > 0.6 ? 206 : 20); + if (p.life > 0.3) t.cellColor(p.life > 0.6 ? 20 : 10, p.life > 0.6 ? 80 : 40, p.life > 0.6 ? 50 : 25); + t.char(p.life > 0.6 ? '█' : p.life > 0.3 ? '▓' : '░'); + t.point(); + t.pop(); + } + } + if (!t.mouseIsPressed) isDragging = false; +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSEDRAGGED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONTINUOUS DRAG EVENT', x, y++, 100, 220, 255); + drawText('Fires continuously while dragging.', x, y++, 140, 160, 190); + drawText('Injects fluid particle streamlines.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('DRAG EVENTS: ' + dragCount, x, y++, 140, 255, 180); + drawText('DRAGGING: ' + (isDragging ? 'TRUE' : 'FALSE'), x, y++, 180, 200, 220); + drawText('PARTICLES: ' + particles.length, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md index 44b5d452..1f0e40bd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md @@ -32,5 +32,90 @@ Register the single-callback handler for mouse movement. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const RAMP = ' .:;ilwW@'; +const labelLayer = t.layers.add(); +const moveHistory = []; +let moveCount = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseMoved(() => { + if (t.mouse.x !== Number.NEGATIVE_INFINITY) { + moveCount++; + moveHistory.unshift({ x: t.mouse.x, y: t.mouse.y, life: 1.0 }); + if (moveHistory.length > 20) moveHistory.length = 20; + } +}); + +t.draw(() => { + t.background(2, 11, 8); + for (let i = moveHistory.length - 1; i >= 0; i--) { + if ((moveHistory[i].life -= 0.025) <= 0) moveHistory.splice(i, 1); + } + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const sweepAngle = (t.frameCount * 0.04) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const elevation = (Math.sin(x * 0.1 + y * 0.05) + Math.cos(x * 0.05 - y * 0.1) + 2) * 0.25; + let angleDiff = Math.abs(Math.atan2(y, x) + Math.PI - sweepAngle); + if (angleDiff > Math.PI) angleDiff = Math.PI * 2 - angleDiff; + const sweepVal = angleDiff < 0.15 ? (1 - angleDiff / 0.15) * 0.6 : 0; + + let maxHeat = 0; + for (let i = 0; i < moveHistory.length; i++) { + const n = moveHistory[i], + d = Math.hypot(x - n.x, y - n.y); + if (d < 12) maxHeat = Math.max(maxHeat, (1 - d / 12) * n.life); + } + + const val = Math.min(1, elevation * 0.35 + sweepVal + maxHeat * 0.85); + if (val > 0.08) { + const charIdx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); + t.push(); + t.translate(x, y); + if (maxHeat > 0.4) { + t.charColor(204, 255, 0); + t.cellColor(20, 45, 10); + } else if (sweepVal > 0.2) { + t.charColor(0, 229, 255); + } else { + const b = val; + t.charColor(Math.floor(8 + b * 20), Math.floor(36 + b * 90), Math.floor(27 + b * 70)); + } + t.char(RAMP[charIdx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSEMOVED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PASSIVE MOVEMENT EVENT', x, y++, 100, 220, 255); + drawText('Fires on hover without clicking.', x, y++, 140, 160, 190); + drawText('Hovering leaves phosphor sonar trails.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('MOVE EVENTS: ' + moveCount, x, y++, 140, 255, 180); + drawText('TRAIL NODES: ' + moveHistory.length, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md index c3f50f87..a12063bf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md @@ -32,5 +32,89 @@ Register the single-callback handler for mouse press events. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +const shocks = []; +let pressCount = 0, + lastDown = 'NONE'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mousePressed(() => { + if (t.mouse.x !== Number.NEGATIVE_INFINITY) { + pressCount++; + lastDown = `(${t.mouse.x}, ${t.mouse.y})`; + shocks.unshift({ x: t.mouse.x, y: t.mouse.y, age: 0, maxAge: 40 }); + if (shocks.length > 10) shocks.length = 10; + } +}); + +t.draw(() => { + t.background(18, 18, 20); + for (let i = shocks.length - 1; i >= 0; i--) { + if (++shocks[i].age >= shocks[i].maxAge) shocks.splice(i, 1); + } + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const isDiag1 = (x + y) % 7 === 0, + isDiag2 = (x - y) % 7 === 0; + const symbol = isDiag1 && isDiag2 ? '+' : isDiag1 ? '/' : isDiag2 ? '\\' : ' '; + + let shockIntensity = 0; + for (let i = 0; i < shocks.length; i++) { + const s = shocks[i], + dist = Math.abs(Math.hypot(x - s.x, y - s.y) - s.age * 1.2); + if (dist < 2.5) shockIntensity += (1 - dist / 2.5) * (1 - s.age / s.maxAge); + } + + if (symbol !== ' ' || shockIntensity > 0.1) { + t.push(); + t.translate(x, y); + if (shockIntensity > 0.4) { + t.charColor(255, 255, 255); + t.cellColor(255, 0, 85); + t.char(symbol === ' ' ? '#' : '+'); + } else if (shockIntensity > 0.15) { + t.charColor(255, 107, 107); + t.cellColor(70, 0, 30); + t.char(symbol === ' ' ? '=' : symbol); + } else { + t.charColor(42, 46, 61); + t.char(symbol); + } + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSEPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DOWN-STROKE PRESS EVENT', x, y++, 100, 220, 255); + drawText('Fires on initial down-stroke.', x, y++, 140, 160, 190); + drawText('Down-stroke fractures truss lines.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('DOWN PRESSES: ' + pressCount, x, y++, 140, 255, 180); + drawText('LAST DOWN: ' + lastDown, x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md index a41a79eb..dbbebf5e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md @@ -32,5 +32,101 @@ Register the single-callback handler for mouse release events. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +const sparks = []; +let tension = 0, + releaseCount = 0, + lastPos = 'NONE'; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseReleased(() => { + if (t.mouse.x === Number.NEGATIVE_INFINITY) return; + releaseCount++; + lastPos = `(${t.mouse.x}, ${t.mouse.y})`; + for (let i = 0; i < 14; i++) { + const a = (i / 14) * Math.PI * 2, + s = (0.8 + Math.random()) * (0.4 + tension * 0.8); + sparks.unshift({ x: t.mouse.x, y: t.mouse.y, vx: Math.cos(a) * s, vy: Math.sin(a) * s, life: 1 }); + } + tension = 0; + if (sparks.length > 70) sparks.length = 70; +}); + +t.draw(() => { + t.background(8, 8, 16); + const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; + tension = isHeld ? Math.min(1, tension + 0.04) : Math.max(0, tension - 0.08); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + for (let y = -hh; y <= hh; y += 2) { + for (let x = -hw; x <= hw; x += 2) { + const d = isHeld ? Math.hypot(x - t.mouse.x, y - t.mouse.y) : 999; + const pull = d < 20 ? (1 - d / 20) * tension * 3 : 0; + const rx = Math.round(x + (isHeld ? (t.mouse.x - x) * (pull / (d + 1)) : 0)); + const ry = Math.round(y + (isHeld ? (t.mouse.y - y) * (pull / (d + 1)) : 0)); + if (rx >= -hw && rx <= hw && ry >= -hh && ry <= hh) { + t.push(); + t.translate(rx, ry); + t.charColor(pull > 0.4 ? 255 : 30, pull > 0.4 ? Math.floor(100 + pull * 155) : 40, pull > 0.4 ? 0 : 70); + if (pull > 0.4) t.cellColor(80, 20, 0); + t.char(pull > 0.4 ? '#' : '+'); + t.point(); + t.pop(); + } + } + } + + for (let i = sparks.length - 1; i >= 0; i--) { + const s = sparks[i]; + s.x += s.vx; + s.y += s.vy; + s.vx *= 0.93; + s.vy *= 0.93; + if ((s.life -= 0.025) <= 0) { + sparks.splice(i, 1); + continue; + } + const sx = Math.round(s.x), + sy = Math.round(s.y); + if (sx >= -hw && sx <= hw && sy >= -hh && sy <= hh) { + t.push(); + t.translate(sx, sy); + t.charColor(s.life > 0.6 ? 255 : 0, s.life > 0.6 ? 255 : 235, 255); + if (s.life > 0.5) t.cellColor(0, 70, 90); + t.char(s.life > 0.7 ? '@' : s.life > 0.4 ? 'O' : '*'); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSERELEASED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: UP-STROKE RELEASE EVENT', x, y++, 100, 220, 255); + drawText('Fires on mouse button release.', x, y++, 140, 160, 190); + drawText('Releasing launches kinetic spark burst.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('TOTAL RELEASES: ' + releaseCount, x, y++, 140, 255, 180); + drawText('LAST RELEASE: ' + lastPos, x, y++, 180, 200, 220); + drawText('TENSION CHARGE: ' + Math.floor(tension * 100) + '%', x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md index aaef85bd..5db1e0ce 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md @@ -32,5 +32,89 @@ Register the single-callback handler for mouse wheel scrolling. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const RAMP = '·:;oO8@█'; +const labelLayer = t.layers.add(); +let scrollDepth = 0, + lastDelta = 0, + scrollCount = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseScrolled((data) => { + lastDelta = data.delta.y; + scrollDepth += data.delta.y * 0.04; + scrollCount++; +}); + +t.draw(() => { + t.background(4, 4, 8); + scrollDepth += 0.012; // Baseline ambient tunnel movement + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const dist = Math.hypot(x, y * 1.3); + let ringPhase = (dist * 0.2 - scrollDepth) % 1.0; + if (ringPhase < 0) ringPhase += 1.0; + + if (ringPhase < 0.4) { + const intensity = 1 - ringPhase / 0.4; + const charIdx = Math.min(RAMP.length - 1, Math.floor(intensity * RAMP.length)); + t.push(); + t.translate(x, y); + + if (dist < 6) { + // Golden Electric center core + t.charColor(255, Math.floor(200 + intensity * 55), 0); + t.cellColor(90, 40, 0); + } else if (dist < 18) { + // Neon Magenta middle tunnel + t.charColor(255, 0, Math.floor(127 + intensity * 128)); + t.cellColor(60, 0, 30); + } else { + // Deep Violet outer rings + t.charColor( + Math.floor(58 + intensity * 80), + Math.floor(28 + intensity * 50), + Math.floor(94 + intensity * 100) + ); + } + + t.char(RAMP[charIdx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSESCROLLED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCROLL DELTA & DEPTH ZOOM', x, y++, 100, 220, 255); + drawText('Fires on mouse wheel or touchpad scroll.', x, y++, 140, 160, 190); + drawText('Scrolling steps depth through tunnel.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('SCROLL EVENTS: ' + scrollCount, x, y++, 140, 255, 180); + drawText('DEPTH POSITION: ' + scrollDepth.toFixed(2), x, y++, 180, 200, 220); + drawText('LAST SCROLL DELTA: ' + lastDelta.toFixed(1), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noLights.md b/api/textmode.js/classes/Textmodifier/methods/noLights.md index c6b935b4..7785ed91 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLights.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLights.md @@ -28,5 +28,56 @@ Useful when you want later draw calls in the same frame to render unlit. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + value = 0.5 + 0.5 * Math.sin(time); + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + if (value > 0.5) t.noLights(); + else t.pointLight([255, 210, 120], { x: 18, y: -18, z: 28 }); + t.rotateY(time * 40); + t.char('#'); + t.charColor(140, 220, 255); + t.sphere(7); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.NOLIGHTS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISABLE LIGHTS', x, y++, 100, 220, 255); + drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); + drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(value > 0.5 ? 'LIGHTS: OFF' : 'LIGHTS: ON', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noLoop.md b/api/textmode.js/classes/Textmodifier/methods/noLoop.md index 876feffd..7938122f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLoop.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLoop.md @@ -28,5 +28,62 @@ Rendering can be resumed later with [loop](loop.md). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let paused = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mousePressed(() => { + if (t.isLooping()) { + paused = true; + t.noLoop(); + t.redraw(); + } else { + paused = false; + t.loop(); + } +}); + +t.draw(() => { + t.background(6, 10, 22); + t.rotateZ(t.frameCount * 4); + t.char('#'); + t.charColor(255, 210, 120); + t.rect(12, 2); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.NOLOOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PAUSE DRAW LOOP', x, y++, 100, 220, 255); + drawText('Click toggles noLoop/loop.', x, y++, 140, 160, 190); + drawText('Events still resume drawing.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = paused ? 'PAUSED' : 'LOOPING'; + drawText(`STATE: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK: TOGGLE LOOP', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noTexture.md b/api/textmode.js/classes/Textmodifier/methods/noTexture.md index 630e394b..a674e29d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/noTexture.md @@ -26,5 +26,91 @@ Clear the active texture for later geometry draws. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const sourceCanvas = document.createElement('canvas'); +sourceCanvas.width = 96; +sourceCanvas.height = 96; +const ctx = sourceCanvas.getContext('2d'); +let source; +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + source = t.createTexture(sourceCanvas); + source.characters(' .:-=+*#%@').cellColorMode('fixed').cellColor(5, 9, 18); +}); + +t.draw(() => { + t.background(5, 9, 20); + if (!ctx || !source) return; + + const hue = (t.frameCount * 2.5) % 360; + const gradient = ctx.createRadialGradient(48, 48, 10, 48, 48, 48); + gradient.addColorStop(0, '#f8fafc'); + gradient.addColorStop(0.45, `hsl(${hue}, 92%, 58%)`); + gradient.addColorStop(1, `hsl(${(hue + 170) % 360}, 88%, 34%)`); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 96); + ctx.fillStyle = '#111827'; + ctx.fillRect(28, 28, 40, 40); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(38, 38, 20, 20); + + spin = (t.frameCount * 1.4) % 360; + t.perspective(58, 0.1, 4096); + t.camera(0, -8, 38, 0, 0, 0); + t.ambientLight(20, 22, 30); + t.pointLight([255, 235, 180], { x: 18, y: -18, z: 30 }); + t.push(); + t.translate(-10, 0, 0); + t.rotateY(spin); + t.rotateX(14); + t.texture(source); + t.sphere(8); + t.pop(); + t.noTexture(); + t.push(); + t.translate(10, 0, 0); + t.rotateY(spin); + t.rotateX(14); + t.char('@'); + t.charColor(245, 245, 210); + t.cellColor(20, 28, 48); + t.sphere(8); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.NOTEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLEAR TEXTURE', x, y++, 100, 220, 255); + drawText('Left sphere samples the source.', x, y++, 140, 160, 190); + drawText('Right sphere ignores it after clear.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noise.md b/api/textmode.js/classes/Textmodifier/methods/noise.md index 4db20f4a..39b6f8c3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noise.md +++ b/api/textmode.js/classes/Textmodifier/methods/noise.md @@ -42,5 +42,61 @@ Noise value in the range `[0, 1]`. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'noise-field', +}); + +const labelLayer = t.layers.add(); +const ramp = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(3, 8, 18); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const time = t.frameCount * 0.018; + + for (let y = 0; y < t.grid.rows; y += 1) { + for (let x = 0; x < t.grid.cols; x += 1) { + const value = t.noise(x * 0.08, y * 0.08, time); + const index = Math.floor(value * (ramp.length - 1)); + t.push(); + t.translate(left + x, top + y); + t.char(ramp[index]); + t.charColor(60 + value * 180, 150 + value * 90, 255); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.NOISE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORGANIC FIELD', x, y++, 100, 220, 255); + drawText('Nearby inputs return close values.', x, y++, 140, 160, 190); + drawText('Z acts like a smooth time axis.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md index 92daf013..be0f07ad 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md @@ -36,5 +36,64 @@ contributes compared to the previous one. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'noise-detail', +}); + +const labelLayer = t.layers.add(); +const ramp = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPanel(offsetX, octaves, falloff) { + const top = -Math.floor(t.grid.rows / 2) + 11; + t.noiseDetail(octaves, falloff); + for (let y = 0; y < Math.min(16, t.grid.rows - 13); y += 1) { + for (let x = 0; x < 20; x += 1) { + const value = t.noise(x * 0.14, y * 0.14, t.frameCount * 0.012); + const index = Math.floor(value * (ramp.length - 1)); + t.push(); + t.translate(offsetX + x, top + y); + t.char(ramp[index]); + t.charColor(90 + value * 150, 140 + value * 100, 255); + t.point(); + t.pop(); + } + } +} + +t.draw(() => { + t.background(5, 8, 18); + drawPanel(-24, 2, 0.35); + drawPanel(4, 7, 0.65); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.NOISEDETAIL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: OCTAVES + FALLOFF', x, y++, 100, 220, 255); + drawText('Left: soft, low detail.', x, y++, 140, 160, 190); + drawText('Right: richer fine texture.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md index c1ce4575..820a996a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md @@ -35,5 +35,63 @@ current random sequence. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const ramp = ' .:-=+*#%@'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawBand(offsetX) { + const top = -Math.floor(t.grid.rows / 2) + 10; + t.noiseSeed('matched-band'); + for (let y = 0; y < Math.min(18, t.grid.rows - 12); y += 1) { + for (let x = 0; x < 18; x += 1) { + const value = t.noise(x * 0.12, y * 0.12, t.frameCount * 0.01); + const index = Math.floor(value * (ramp.length - 1)); + t.push(); + t.translate(offsetX + x, top + y); + t.char(ramp[index]); + t.charColor(80 + value * 160, 255, 130 + value * 100); + t.point(); + t.pop(); + } + } +} + +t.draw(() => { + t.background(5, 10, 18); + drawBand(-22); + drawBand(4); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.NOISESEED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: REPEATABLE FIELDS', x, y++, 100, 220, 255); + drawText('Both bands use the same seed.', x, y++, 140, 160, 190); + drawText('Same coordinates make same values.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/norm.md b/api/textmode.js/classes/Textmodifier/methods/norm.md index 81217f9e..af862986 100644 --- a/api/textmode.js/classes/Textmodifier/methods/norm.md +++ b/api/textmode.js/classes/Textmodifier/methods/norm.md @@ -41,5 +41,67 @@ The normalized value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let normalized = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 7, 17); + const low = -18; + const high = 18; + raw = t.sin(t.frameCount * 0.04) * 20 + t.cos(t.frameCount * 0.018) * 4; + normalized = t.norm(raw, low, high); + + for (let i = 0; i <= 36; i++) { + const u = i / 36; + const x = -18 + i; + t.push(); + t.translate(x, 4); + t.char(u <= t.constrain(normalized, 0, 1) ? '#' : '.'); + t.charColor(80 + u * 160, 140 + u * 100, 255 - u * 100); + t.point(); + t.pop(); + } + + t.char('|'); + t.charColor(255, 210, 100); + const marker = t.map(t.constrain(normalized, 0, 1), 0, 1, low, high); + t.line(marker, -7, marker, 9); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.NORM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RANGE TO 0..1', x, y++, 100, 220, 255); + drawText('norm(value, low, high) scales.', x, y++, 140, 160, 190); + drawText('This bar clamps only for display.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`NORM: ${normalized.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ortho.md b/api/textmode.js/classes/Textmodifier/methods/ortho.md index 28a4fbe6..7925a172 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ortho.md +++ b/api/textmode.js/classes/Textmodifier/methods/ortho.md @@ -38,5 +38,55 @@ The projection mode is reset to perspective at the beginning of each frame. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + t.ortho(); + t.camera(0, 0, 42); + for (let i = 0; i < 3; i++) { + t.push(); + t.translate((i - 1) * 9, 0, i * -12); + t.rotateY(t.frameCount + i * 35); + t.char('+'); + t.charColor(120 + i * 40, 220, 255); + t.box(6, 6, 6); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ORTHO', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORTHO PROJECTION', x, y++, 100, 220, 255); + drawText('Depth no longer changes scale.', x, y++, 140, 160, 190); + drawText('Boxes keep equal apparent size.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.ortho()', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/perspective.md b/api/textmode.js/classes/Textmodifier/methods/perspective.md index fad2d1c6..7ee913bb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/perspective.md +++ b/api/textmode.js/classes/Textmodifier/methods/perspective.md @@ -39,5 +39,57 @@ The default perspective is tuned to match textmode.js legacy depth behavior. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let fov = 60; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + fov = 60 + Math.sin(t.frameCount * 0.03) * 25; + t.perspective(fov, 0.1, 4096); + t.camera(0, 0, 44, 0, 0, 0); + for (let i = 0; i < 3; i++) { + t.push(); + t.translate((i - 1) * 8, 0, i * -12); + t.char('#'); + t.charColor(120 + i * 40, 220, 255 - i * 20); + t.box(6, 6, 6); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.PERSPECTIVE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FOV PROJECTION', x, y++, 100, 220, 255); + drawText('FOV breathes wide to narrow.', x, y++, 140, 160, 190); + drawText('Depth changes apparent size.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FOV: ${fov.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pinch.md b/api/textmode.js/classes/Textmodifier/methods/pinch.md index 05f83004..0faf89d5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pinch.md +++ b/api/textmode.js/classes/Textmodifier/methods/pinch.md @@ -35,5 +35,60 @@ the initial distance and the change since the previous update, enabling zoom int ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let scale = 1; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.pinch((data) => { + scale = Math.max(0.3, Math.min(4, data.scale)); +}); + +t.mouseScrolled((data) => { + scale = Math.max(0.3, Math.min(4, scale - data.delta.y * 0.01)); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.push(); + t.rotateZ(t.frameCount * 0.5); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(8 * scale, 8 * scale); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.PINCH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PINCH SCALE', x, y++, 100, 220, 255); + drawText('Pinch or scroll changes scale.', x, y++, 140, 160, 190); + drawText('Shape size follows gesture.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SCALE: ${scale.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md index 92d6371d..b29b42b5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md +++ b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md @@ -30,7 +30,90 @@ Current pixel density. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let density = 1; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + density = density === 1 ? 2 : 1; + t.pixelDensity(density); +}); + +t.draw(() => { + t.background(6, 10, 22); + + // Crosshair pattern: higher pixel density yields finer lines. + const step = 4; + const max = 18; + t.cellColor(20, 25, 45); + for (let i = -max; i <= max; i += step) { + t.rect(1, 1); + t.translate(1, 0); + t.point(); + } + for (let i = -max; i <= max; i += step) { + t.push(); + t.translate(0, i); + t.rect(1, 1); + t.pop(); + } + + // Diagonal stepped line: smoother at higher resolution. + t.cellColor(60, 140, 200); + t.push(); + t.translate(-4, -4); + for (let i = 0; i < 9; i++) { + t.char('#'); + t.point(); + t.translate(1, 1); + } + t.pop(); + + // Pulse ring that reveals grid density. + const radius = 8 + Math.sin(t.frameCount * 0.05) * 3; + t.cellColor(200, 120, 60); + t.char('*'); + t.charColor(200, 120, 60); + t.ellipse(radius * 2, radius); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.PIXELDENSITY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RETINA RENDERING', x, y++, 100, 220, 255); + drawText('Click to toggle pixel density.', x, y++, 140, 160, 190); + drawText('Backing store scales, CSS fixed.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DENSITY: ${t.pixelDensity()}x`, x, y++, 140, 255, 180); + drawText(`BACKING: ${t.width}x${t.height}`, x, y++, 140, 255, 180); + drawText(`GRID: ${t.grid.cols}x${t.grid.rows}`, x, y++, 100, 200, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -54,5 +137,87 @@ This resizes the canvas backing store while keeping the CSS display size unchang ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let density = 1; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + density = density === 1 ? 2 : 1; + t.pixelDensity(density); +}); + +t.draw(() => { + t.background(6, 10, 22); + + // Crosshair pattern: higher pixel density yields finer lines. + const step = 4; + const max = 18; + t.cellColor(20, 25, 45); + for (let i = -max; i <= max; i += step) { + t.rect(1, 1); + t.translate(1, 0); + t.point(); + } + for (let i = -max; i <= max; i += step) { + t.push(); + t.translate(0, i); + t.rect(1, 1); + t.pop(); + } + + // Diagonal stepped line: smoother at higher resolution. + t.cellColor(60, 140, 200); + t.push(); + t.translate(-4, -4); + for (let i = 0; i < 9; i++) { + t.char('#'); + t.point(); + t.translate(1, 1); + } + t.pop(); + + // Pulse ring that reveals grid density. + const radius = 8 + Math.sin(t.frameCount * 0.05) * 3; + t.cellColor(200, 120, 60); + t.char('*'); + t.charColor(200, 120, 60); + t.ellipse(radius * 2, radius); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.PIXELDENSITY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RETINA RENDERING', x, y++, 100, 220, 255); + drawText('Click to toggle pixel density.', x, y++, 140, 160, 190); + drawText('Backing store scales, CSS fixed.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DENSITY: ${t.pixelDensity()}x`, x, y++, 140, 255, 180); + drawText(`BACKING: ${t.width}x${t.height}`, x, y++, 140, 255, 180); + drawText(`GRID: ${t.grid.cols}x${t.grid.rows}`, x, y++, 100, 200, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/point.md b/api/textmode.js/classes/Textmodifier/methods/point.md index 7e60ace6..44cd8323 100644 --- a/api/textmode.js/classes/Textmodifier/methods/point.md +++ b/api/textmode.js/classes/Textmodifier/methods/point.md @@ -26,5 +26,55 @@ Draw one cell with the current settings. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const count = 24; + for (let i = 0; i < count; i++) { + const angle = t.frameCount * 0.03 + (i / count) * Math.PI * 2; + const radius = 5 + (i % 4) * 2; + t.push(); + t.translate(Math.cos(angle) * radius * 1.6, Math.sin(angle) * radius); + t.char(i % 2 === 0 ? '+' : '.'); + t.charColor(120 + i * 4, 180, 255 - i * 3); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POINT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DRAW ONE CELL', x, y++, 100, 220, 255); + drawText('point() stamps the active glyph.', x, y++, 140, 160, 190); + drawText('Each dot uses its own transform.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.point()', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pointLight.md b/api/textmode.js/classes/Textmodifier/methods/pointLight.md index 9ba2c979..6179a6f8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pointLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/pointLight.md @@ -48,7 +48,59 @@ Up to five point lights are supported per frame. Additional calls are ignored. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + value = 0.5 + 0.5 * Math.sin(time); + t.perspective(58, 0.1, 4096); + t.camera(16, -10, 42, 0, 0, 0); + t.ambientLight(20, 20, 28); + t.pointLight([255, 210, 120], { x: Math.sin(time) * 24, y: -18, z: 28 }); + t.rotateY(time * 40); + t.char('#'); + t.charColor(140, 220, 255); + t.sphere(7); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POINTLIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POINT LIGHT', x, y++, 100, 220, 255); + drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); + drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SWEEP: ${value.toFixed(2)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/pop.md b/api/textmode.js/classes/Textmodifier/methods/pop.md index f502393b..b3a64fe8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pop.md +++ b/api/textmode.js/classes/Textmodifier/methods/pop.md @@ -27,5 +27,55 @@ Use with [push](push.md) to isolate style changes within a block. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + t.push(); + t.rotateZ(time * 30); + t.translate(10, 0); + t.char('#'); + t.charColor(140, 255, 180); + t.rect(4, 3); + t.pop(); + t.charColor(255, 210, 120); + t.char('+'); + t.rect(5, 1); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESTORE STATE', x, y++, 100, 220, 255); + drawText('pop() returns to prior state.', x, y++, 140, 160, 190); + drawText('Center mark is not rotated.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.pop()', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pow.md b/api/textmode.js/classes/Textmodifier/methods/pow.md index c54cf5fb..55ebd98a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pow.md +++ b/api/textmode.js/classes/Textmodifier/methods/pow.md @@ -35,5 +35,64 @@ Base raised to the exponent. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let exponent = 1; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 17); + exponent = 0.5 + t.norm(t.sin(t.frameCount * 0.03) + t.cos(t.frameCount * 0.017) * 0.4, -1.4, 1.4) * 3; + + for (let i = 0; i <= 40; i++) { + const u = i / 40; + const shaped = t.pow(u, exponent); + const x = -20 + i; + const y = 8 - shaped * 16; + const heat = shaped; + t.push(); + t.translate(x, y); + t.char(heat > 0.7 ? '#' : heat > 0.3 ? '+' : '.'); + t.charColor(90 + heat * 150, 150 + heat * 80, 255 - heat * 90); + t.point(); + t.pop(); + } + + t.char('-'); + t.charColor(65, 85, 125); + t.line(-20, 8, 20, 8); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POW', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CURVE SHAPING', x, y++, 100, 220, 255); + drawText('pow(base, exp) bends 0..1.', x, y++, 140, 160, 190); + drawText('Small exponents lift the curve.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`EXPONENT: ${exponent.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/print.md b/api/textmode.js/classes/Textmodifier/methods/print.md index abf6df43..29f42df9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/print.md +++ b/api/textmode.js/classes/Textmodifier/methods/print.md @@ -46,5 +46,72 @@ like `[fg=red]`, `[bg=color]`, `[inv]`, `[rot=90]`, `[fx]`, `[fy]`, and their cl ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 22); + + // Subtle dynamic background particles + for (let i = 0; i < 15; i++) { + const angle = t.frameCount * 0.02 + i; + const radius = 8 + (i % 3) * 2.5; + t.push(); + t.translate(Math.cos(angle) * radius * 1.6, Math.sin(angle) * radius); + t.charColor(30, 45, 80); + t.char(i % 2 === 0 ? '.' : '+'); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.charColor(100, 255, 140); + t.print('TEXTMODIFIER.PRINT', x, y++); + t.pop(); + + t.push(); + t.charColor(80, 100, 150); + t.print('------------------------------------', x, y++); + t.pop(); + + t.push(); + t.charColor(100, 220, 255); + t.print('CONCEPT: NATIVE RICH TYPOGRAPHY', x, y++); + t.pop(); + + t.push(); + t.charColor(140, 160, 190); + t.print('Prints strings with inline BBCode-style tags:', x, y++); + t.print(' - [fg=green]Foreground Color[/fg]', x, y++); + t.print(' - [bg=blue]Background Color[/bg]', x, y++); + t.print(' - [inv]Inverted colors[/inv]', x, y++); + t.print(' - [rot=90]Rotated[/rot] [fx]Flip X[/fx] [fy]Flip Y[/fy]', x, y++); + t.pop(); + + t.push(); + t.charColor(80, 100, 150); + t.print('------------------------------------', x, y++); + t.pop(); + + t.print('NESTED: [fg=yellow][inv][rot=180] LEVEL 05 [/rot][/inv][/fg] | STATUS: [fg=red]CRITICAL[/fg]', x, y++); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/printAlign.md b/api/textmode.js/classes/Textmodifier/methods/printAlign.md index 46a7c0b1..8da83594 100644 --- a/api/textmode.js/classes/Textmodifier/methods/printAlign.md +++ b/api/textmode.js/classes/Textmodifier/methods/printAlign.md @@ -33,5 +33,99 @@ Sets the text alignment rules for subsequent `print` calls. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); +const labelLayer = t.layers.add(); + +const alignments = [ + ['left', 'top'], + ['center', 'top'], + ['right', 'top'], + ['left', 'middle'], + ['center', 'middle'], + ['right', 'middle'], + ['left', 'bottom'], + ['center', 'bottom'], + ['right', 'bottom'], +]; + +const placementAlign = { left: 'right', center: 'center', right: 'left' }; +const placementVerticalAlign = { top: 'bottom', middle: 'middle', bottom: 'top' }; + +t.draw(() => { + t.background(6, 10, 22); + + const cols = t.grid.cols; + const rows = t.grid.rows; + t.push(); + t.charColor(20, 25, 45); + for (let y = -Math.floor(rows / 2); y < Math.floor(rows / 2); y += 4) { + for (let x = -Math.floor(cols / 2); x < Math.floor(cols / 2); x += 4) { + t.push(); + t.translate(x, y); + t.char('+'); + t.point(); + t.pop(); + } + } + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const bottom = Math.floor(t.grid.rows / 2); + const index = Math.floor(t.frameCount / 90) % alignments.length; + const [h, v] = alignments[index]; + const label = `${h}, ${v}`; + const labelX = h === 'left' ? -1 : h === 'right' ? 1 : 0; + const labelY = v === 'top' ? -1 : v === 'bottom' ? 1 : 0; + + t.push(); + t.char('O'); + t.charColor(255, 100, 100); + t.invert(true); + t.point(); + t.pop(); + + t.push(); + t.printAlign(placementAlign[h], placementVerticalAlign[v]); + t.charColor(100, 220, 255); + t.print( + `ALIGNMENT: [fg=yellow][inv] ${label.toUpperCase()} [/inv][/fg]\nAnchor: (0, 0)\nLines: 5\nHorizontal: ${h}\nVertical: ${v}`, + labelX, + labelY + ); + t.pop(); + + t.push(); + t.printAlign('center', 'top'); + t.charColor(100, 255, 140); + t.print('TEXTMODIFIER.PRINTALIGN', 0, top + 2); + + t.charColor(80, 100, 150); + t.print('------------------------------------------------', 0, top + 3); + + t.charColor(140, 160, 190); + t.print('Anchored typography positioning demo. \nCycles automatically.', 0, top + 4); + t.pop(); + + t.push(); + t.printAlign('center', 'bottom'); + t.charColor(80, 100, 150); + t.print('------------------------------------------------', 0, bottom - 3); + t.charColor(120, 130, 150); + t.print(`Active state: ${index + 1} of ${alignments.length} | Frame: ${t.frameCount}`, 0, bottom - 2); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/push.md b/api/textmode.js/classes/Textmodifier/methods/push.md index 19bbf2af..53437ae0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/push.md +++ b/api/textmode.js/classes/Textmodifier/methods/push.md @@ -27,5 +27,57 @@ Use with [pop](pop.md) to isolate style changes within a block. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + for (let i = 0; i < 5; i++) { + t.push(); + t.rotateZ(time * 20 + i * 72); + t.translate(8 + i, 0); + t.char('*'); + t.charColor(120 + i * 20, 220, 255 - i * 20); + t.point(); + t.pop(); + } + t.charColor(255, 210, 120); + t.char('+'); + t.point(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.PUSH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SAVE STATE', x, y++, 100, 220, 255); + drawText('push() stores transform state.', x, y++, 140, 160, 190); + drawText('Each spoke restores cleanly.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.push()', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/radians.md b/api/textmode.js/classes/Textmodifier/methods/radians.md index d769dd6c..f5766b72 100644 --- a/api/textmode.js/classes/Textmodifier/methods/radians.md +++ b/api/textmode.js/classes/Textmodifier/methods/radians.md @@ -34,5 +34,76 @@ Angle in radians. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let angle = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawPoint(x, y) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); +} + +t.draw(() => { + t.background(7, 9, 18); + angle = (t.frameCount * 2 + t.mouse.x * 2) % 360; + const radians = t.radians(angle); + + t.char('.'); + t.charColor(45, 55, 86); + for (let r = 3; r <= 9; r += 3) t.ellipse(r * 2, r * 2); + + for (let i = 0; i < 10; i++) { + const a = radians + i * 0.45; + const radius = 3 + i * 0.65; + const x = Math.cos(a) * radius; + const y = Math.sin(a) * radius; + const fade = t.map(i, 0, 9, 255, 80); + t.char(i === 0 ? '@' : '+'); + t.charColor(120, fade, 255 - i * 10); + drawPoint(x, y); + } + + t.push(); + t.rotate(angle); + t.char('>'); + t.charColor(255, 220, 120); + t.line(0, 0, 10, 0); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RADIANS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DEGREE TO RADIAN', x, y++, 100, 220, 255); + drawText('radians() feeds sin and cos.', x, y++, 140, 160, 190); + drawText('The spiral uses circular math.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ANGLE: ${angle.toFixed(1)} DEG`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/random.md b/api/textmode.js/classes/Textmodifier/methods/random.md index 753ee3f0..aa2815cc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/random.md +++ b/api/textmode.js/classes/Textmodifier/methods/random.md @@ -34,7 +34,65 @@ Random number in the range [0, 1). ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'random-demo', +}); + +const labelLayer = t.layers.add(); +const characters = Array.from('░▒▓█+*#'); +let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (t.frameCount % 12 === 1) { + mark = { + x: Math.floor(t.random(-18, 18)), + y: Math.floor(t.random(-9, 9)), + char: t.random(characters) ?? '*', + r: Math.floor(t.random(120, 256)), + g: Math.floor(t.random(120, 256)), + b: Math.floor(t.random(120, 256)), + }; + } + + t.push(); + t.translate(mark.x, mark.y); + t.char(mark.char); + t.charColor(mark.r, mark.g, mark.b); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); + drawText('The mark uses random ranges.', x, y++, 140, 160, 190); + drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -58,7 +116,65 @@ Random number in the range [0, max). ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'random-demo', +}); + +const labelLayer = t.layers.add(); +const characters = Array.from('░▒▓█+*#'); +let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (t.frameCount % 12 === 1) { + mark = { + x: Math.floor(t.random(-18, 18)), + y: Math.floor(t.random(-9, 9)), + char: t.random(characters) ?? '*', + r: Math.floor(t.random(120, 256)), + g: Math.floor(t.random(120, 256)), + b: Math.floor(t.random(120, 256)), + }; + } + + t.push(); + t.translate(mark.x, mark.y); + t.char(mark.char); + t.charColor(mark.r, mark.g, mark.b); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); + drawText('The mark uses random ranges.', x, y++, 140, 160, 190); + drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -83,7 +199,65 @@ Random number in the range [min, max). ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'random-demo', +}); + +const labelLayer = t.layers.add(); +const characters = Array.from('░▒▓█+*#'); +let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (t.frameCount % 12 === 1) { + mark = { + x: Math.floor(t.random(-18, 18)), + y: Math.floor(t.random(-9, 9)), + char: t.random(characters) ?? '*', + r: Math.floor(t.random(120, 256)), + g: Math.floor(t.random(120, 256)), + b: Math.floor(t.random(120, 256)), + }; + } + + t.push(); + t.translate(mark.x, mark.y); + t.char(mark.char); + t.charColor(mark.r, mark.g, mark.b); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); + drawText('The mark uses random ranges.', x, y++, 140, 160, 190); + drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -113,5 +287,62 @@ A random array element, or `undefined` when the array is empty. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'random-demo', +}); + +const labelLayer = t.layers.add(); +const characters = Array.from('░▒▓█+*#'); +let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (t.frameCount % 12 === 1) { + mark = { + x: Math.floor(t.random(-18, 18)), + y: Math.floor(t.random(-9, 9)), + char: t.random(characters) ?? '*', + r: Math.floor(t.random(120, 256)), + g: Math.floor(t.random(120, 256)), + b: Math.floor(t.random(120, 256)), + }; + } + + t.push(); + t.translate(mark.x, mark.y); + t.char(mark.char); + t.charColor(mark.r, mark.g, mark.b); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); + drawText('The mark uses random ranges.', x, y++, 140, 160, 190); + drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md index c4d7c6b2..24f49239 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md @@ -39,5 +39,83 @@ Gaussian random number. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'gaussian-cloud', +}); + +const labelLayer = t.layers.add(); +const samples = []; +let latest = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addSample() { + latest = t.randomGaussian(0, 6); + samples.push(latest); + if (samples.length > 180) { + samples.shift(); + } +} + +t.draw(() => { + t.background(4, 7, 16); + for (let i = 0; i < 4; i++) { + addSample(); + } + + t.char('.'); + t.charColor(45, 60, 95); + for (let x = -24; x <= 24; x += 2) { + t.line(x, 9, x, 10); + } + + for (let i = 0; i < samples.length; i++) { + const age = i / samples.length; + const x = t.constrain(t.round(samples[i]), -24, 24); + const y = 8 - t.floor(age * 16); + t.push(); + t.translate(x, y); + t.char(age > 0.7 ? '*' : age > 0.35 ? '+' : '.'); + t.charColor(90 + age * 140, 150 + age * 90, 255); + t.point(); + t.pop(); + } + + t.char('|'); + t.charColor(255, 205, 90); + t.line(0, -10, 0, 10); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.RANDOMGAUSSIAN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SEEDED BELL CURVE', x, y++, 100, 220, 255); + drawText('Most samples gather near mean 0.', x, y++, 140, 160, 190); + drawText('Standard deviation sets spread.', x, y++, 140, 160, 190); + drawText('The sequence is reproducible.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`LATEST: ${latest.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`SAMPLES: ${samples.length}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md index 2f3068d6..f68f9097 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md @@ -35,5 +35,69 @@ stream lookups are derived from the new root seed. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const points = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function rebuildPoints() { + t.randomSeed('repeatable-grid'); + points.length = 0; + for (let i = 0; i < 28; i++) { + points.push({ + x: Math.floor(t.random(-20, 20)), + y: Math.floor(t.random(-9, 9)), + char: t.random(['.', '+', '*', '#']) ?? '.', + }); + } +} + +rebuildPoints(); + +t.draw(() => { + t.background(8, 7, 18); + if (t.frameCount % 120 === 1) { + rebuildPoints(); + } + + for (const point of points) { + t.push(); + t.translate(point.x, point.y); + t.char(point.char); + t.charColor(120, 240, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOMSEED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESET SEQUENCE', x, y++, 100, 220, 255); + drawText('The same points return.', x, y++, 140, 160, 190); + drawText('The seed is set every loop.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/randomStream.md b/api/textmode.js/classes/Textmodifier/methods/randomStream.md index 07d45910..821030c3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomStream.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomStream.md @@ -37,5 +37,62 @@ A deterministic random generator for the given stream name. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + seed: 'stream-demo', +}); + +const labelLayer = t.layers.add(); +const leftStream = t.randomStream('left'); +const rightStream = t.randomStream('right'); +let leftY = 0; +let rightY = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 18); + if (t.frameCount % 16 === 1) { + leftY = Math.floor(leftStream.random(-9, 9)); + rightY = Math.floor(rightStream.random(-9, 9)); + } + + t.push(); + t.translate(-8, leftY); + t.char('L'); + t.charColor(130, 255, 190); + t.point(); + t.translate(16, rightY - leftY); + t.char('R'); + t.charColor(255, 190, 130); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RANDOMSTREAM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: NAMED STREAMS', x, y++, 100, 220, 255); + drawText('Left and right are separate.', x, y++, 140, 160, 190); + drawText('One stream cannot move another.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rect.md b/api/textmode.js/classes/Textmodifier/methods/rect.md index 0508fdec..4e9ca472 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rect.md +++ b/api/textmode.js/classes/Textmodifier/methods/rect.md @@ -34,5 +34,59 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let widthCells = 0; +let heightCells = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + widthCells = 12 + Math.round(Math.sin(time) * 5); + heightCells = 6 + Math.round(Math.cos(time * 0.8) * 3); + t.push(); + t.translate(8, 1); + t.rotateZ(Math.sin(time) * 8); + t.char('#'); + t.charColor(120, 220, 255); + t.cellColor(20, 30, 60); + t.rect(widthCells, heightCells); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RECT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RECTANGLE SHAPE', x, y++, 100, 220, 255); + drawText('Draws width by height cells.', x, y++, 140, 160, 190); + drawText('Scene shifted clear of the HUD.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`W: ${widthCells}`, x, y++, 140, 255, 180); + drawText(`H: ${heightCells}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/redraw.md b/api/textmode.js/classes/Textmodifier/methods/redraw.md index 0f1fb4b9..024a063e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/redraw.md +++ b/api/textmode.js/classes/Textmodifier/methods/redraw.md @@ -35,5 +35,79 @@ allowing you to trigger rendering on demand. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let steps = 0; +let lastRequest = 1; + +t.setup(() => { + t.noLoop(); +}); + +t.mousePressed(() => { + lastRequest = 1; + t.redraw(); +}); + +t.keyPressed(() => { + lastRequest = 5; + t.redraw(5); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + steps++; + t.background(6, 8, 14); + + const width = Math.max(12, Math.floor(t.grid.cols * 0.6)); + for (let i = 0; i < width; i++) { + const phase = steps * 0.32 + i * 0.45; + const x = i - Math.floor(width / 2); + const y = Math.round(Math.sin(phase) * 5); + t.push(); + t.translate(x, y + 2); + t.char(i % 3 === 0 ? '+' : '*'); + t.charColor(90 + (i % 12) * 12, 200, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.REDRAW', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MANUAL RENDER STEPS', x, y++, 100, 220, 255); + drawText('setup pauses with noLoop().', x, y++, 140, 160, 190); + drawText('redraw(n) renders n frames.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FRAMES: ${steps}`, x, y++, 140, 255, 180); + drawText(`LAST REQUEST: ${lastRequest}`, x, y++, 255, 225, 140); + drawText('CLICK: REDRAW 1', x, y++, 255, 225, 140); + drawText('ANY KEY: REDRAW 5', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md index 65a03198..a81bcc4b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md @@ -33,5 +33,97 @@ otherwise `false`. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let rotX = 0, + rotY = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (document.pointerLockElement === t.canvas) t.exitPointerLock(); + else t.requestPointerLock(); +}); + +t.draw(() => { + t.background(5, 8, 10); + const isLocked = document.pointerLockElement === t.canvas; + + if (isLocked) { + rotX += t.movedX * 0.35; + rotY += t.movedY * 0.35; + } else { + rotX += 0.25; + } + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const rad = Math.floor(Math.min(hw, hh) * 0.65); + const angleOffset = (rotX * 0.05) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y * 1.4); + const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; + + let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; + let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); + let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; + + if (isRing || isAxis || isTick) { + t.push(); + t.translate(x, y); + + if (isLocked) { + if (d < 3) { + t.charColor(255, 51, 51); + t.cellColor(90, 0, 0); + t.char('+'); + } else if (isTick) { + t.charColor(255, 200, 0); + t.char('#'); + } else { + t.charColor(255, 153, 0); + t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); + } + } else { + t.charColor(68, 85, 102); + t.char(isAxis ? '+' : '.'); + } + + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isLocked = document.pointerLockElement === t.canvas; + + drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); + drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); + drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); + drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); + drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md index d4cb7ddf..6c550c3b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md @@ -28,5 +28,56 @@ This clears any active explicit camera and returns view calculation to renderer- ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let custom = true; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + custom = Math.floor(t.frameCount / 120) % 2 === 0; + if (custom) { + t.camera(Math.sin(t.frameCount * 0.03) * 20, 10, 38, 0, 0, 0); + } else { + t.resetCamera(); + } + t.char('#'); + t.charColor(140, 220, 255); + t.rotateY(t.frameCount); + t.box(8, 8, 8); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RESETCAMERA', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESTORE CAMERA', x, y++, 100, 220, 255); + drawText('Alternates custom and reset.', x, y++, 140, 160, 190); + drawText('resetCamera returns auto view.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(custom ? 'MODE: CUSTOM' : 'MODE: RESET', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md index 9357366f..f37deea7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md @@ -28,5 +28,57 @@ This clears translation, rotation, and scale state for subsequent draw calls. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.04; + t.push(); + t.rotateZ(time * 40); + t.translate(12, 0); + t.charColor(120, 220, 255); + t.char('#'); + t.rect(6, 3); + t.resetMatrix(); + t.charColor(255, 210, 120); + t.translate(8, 3); + t.char('+'); + t.rect(5, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RESETMATRIX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLEAR TRANSFORM', x, y++, 100, 220, 255); + drawText('resetMatrix drops transforms.', x, y++, 140, 160, 190); + drawText('Yellow bar uses fresh matrix.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.resetMatrix()', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/resetShader.md b/api/textmode.js/classes/Textmodifier/methods/resetShader.md index 1afd5768..9bf9a0c8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetShader.md @@ -29,5 +29,72 @@ Equivalent to calling `shader(null)`. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let shaderObj; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_texCoord; + out vec2 v_uv; + void main(){gl_Position=a_position;v_uv=a_texCoord;}`; + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform float u_time; + layout(location=0) out vec4 o_character; + layout(location=1) out vec4 o_primaryColor; + layout(location=2) out vec4 o_secondaryColor; + void main(){float v=fract(v_uv.x*8.0+u_time);o_character=vec4(v,0,0,1);o_primaryColor=vec4(v,0.8,1.0,1);o_secondaryColor=vec4(0.02,0.04,0.08,1);}`; + shaderObj = await t.createShader(vert, frag); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (shaderObj && Math.floor(t.frameCount / 90) % 2 === 0) { + t.shader(shaderObj); + t.setUniform('u_time', t.frameCount * 0.02); + } + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); + t.char('#'); + t.charColor(255, 210, 120); + t.rect(10, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RESETSHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESTORE SHADER', x, y++, 100, 220, 255); + drawText('Shader affects the main drawing.', x, y++, 140, 160, 190); + drawText('resetShader restores default.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('RESET AFTER FULLSCREEN', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md index 35e721cf..dbf0ebf1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md +++ b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md @@ -33,5 +33,54 @@ Resize the canvas and adjust all related components accordingly. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let resized = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.mouseClicked(() => { + resized++; + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.RESIZECANVAS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESIZE CANVAS', x, y++, 100, 220, 255); + drawText('Click calls resizeCanvas.', x, y++, 140, 160, 190); + drawText('Window callback does the same.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CLICKS: ${resized}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rotate.md b/api/textmode.js/classes/Textmodifier/methods/rotate.md index 3e016ae2..c86e6d38 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotate.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotate.md @@ -30,7 +30,78 @@ All geometries rotate around the center of the shape. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 8, 20); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.04; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const angle = Math.atan2(y, x); + + const wave = Math.sin(dist * 0.25 - tm * 2) * Math.cos(angle * 6 + tm); + const norm = (wave + 1) * 0.5; + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.rotate(Math.sin(tm * 0.5) * 0.2); + t.translate(x, y); + t.charColor(Math.floor(80 + norm * 175), Math.floor(180 + norm * 75), Math.floor(255 - norm * 100)); + t.cellColor(Math.floor(6 + norm * 12), Math.floor(12 + norm * 14), Math.floor(28 + norm * 18)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.ROTATE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: MOIRE SPIROGRAPH CITADEL', x, y++); + t.charColor(140, 160, 190); + t.print('Rotates current coordinate space', x, y++); + t.print('by specified angle in 2D plane.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('ROTATION: FULL-SCREEN HARMONIC MOIRE', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md index 91ba4265..449ce5e2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md @@ -35,5 +35,64 @@ along with the gesture centre in grid coordinates. Ideal for dial-like interacti ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let rotation = 0; +let dragStart = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.rotateGesture((data) => { + rotation += data.deltaRotation; +}); + +t.mousePressed(() => { + dragStart = t.mouse.x; +}); + +t.mouseDragged(() => { + rotation += (t.mouse.x - dragStart) * 0.5; + dragStart = t.mouse.x; +}); + +t.draw(() => { + t.background(6, 10, 22); + t.rotateZ(rotation); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(14, 4); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ROTATEGESTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ROTATE GESTURE', x, y++, 100, 220, 255); + drawText('Touch twist or drag rotates.', x, y++, 140, 160, 190); + drawText('Rotation accumulates over time.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DEG: ${rotation.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateX.md b/api/textmode.js/classes/Textmodifier/methods/rotateX.md index b6911c70..f57542dc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateX.md @@ -36,5 +36,58 @@ Current X-axis rotation in degrees when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.04; + value = (time * 70) % 360; + t.charColor(50, 60, 90); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + t.push(); + t.rotateX(value); + t.char('#'); + t.charColor(140, 255, 180); + t.rect(6, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ROTATEX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: X AXIS ROTATION', x, y++, 100, 220, 255); + drawText('Pitch changes vertical plane.', x, y++, 140, 160, 190); + drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateY.md b/api/textmode.js/classes/Textmodifier/methods/rotateY.md index 84a59c55..4c2ca0ad 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateY.md @@ -36,5 +36,58 @@ Current Y-axis rotation in degrees when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.04; + value = (time * 70) % 360; + t.charColor(50, 60, 90); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + t.push(); + t.rotateY(value); + t.char('#'); + t.charColor(140, 255, 180); + t.rect(6, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ROTATEY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: Y AXIS ROTATION', x, y++, 100, 220, 255); + drawText('Yaw turns the rectangle.', x, y++, 140, 160, 190); + drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md index ff62b38e..96c799e4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md @@ -36,5 +36,58 @@ Current Z-axis rotation in degrees when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.04; + value = (time * 70) % 360; + t.charColor(50, 60, 90); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + t.push(); + t.rotateZ(value); + t.char('#'); + t.charColor(140, 255, 180); + t.rect(6, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ROTATEZ', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: Z AXIS ROTATION', x, y++, 100, 220, 255); + drawText('Roll matches 2D rotation.', x, y++, 140, 160, 190); + drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/round.md b/api/textmode.js/classes/Textmodifier/methods/round.md index 03c41731..b25aba48 100644 --- a/api/textmode.js/classes/Textmodifier/methods/round.md +++ b/api/textmode.js/classes/Textmodifier/methods/round.md @@ -35,5 +35,69 @@ Rounded value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let raw = 0; +let coarse = 0; +let decimal = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 16); + raw = t.sin(t.frameCount * 0.037) * 12 + t.cos(t.frameCount * 0.019) * 3; + coarse = t.round(raw); + decimal = t.round(raw, 1); + + for (let x = -22; x <= 22; x++) { + const isCoarse = x === coarse; + t.push(); + t.translate(x, 2 + t.sin(x * 0.4 + t.frameCount * 0.04) * 4); + t.char(isCoarse ? '#' : '.'); + t.charColor(isCoarse ? 255 : 55, isCoarse ? 215 : 80, isCoarse ? 100 : 120); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(120, 245, 255); + t.push(); + t.translate(decimal, -6); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.ROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: NEAREST VALUE', x, y++, 100, 220, 255); + drawText('round() snaps to the closest cell.', x, y++, 140, 160, 190); + drawText('round(value, 1) keeps one decimal.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`ROUND: ${coarse}`, x, y++, 220, 230, 255); + drawText(`ROUND.1: ${decimal.toFixed(1)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/scale.md b/api/textmode.js/classes/Textmodifier/methods/scale.md index 1ffb5029..dd9c16c0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/scale.md +++ b/api/textmode.js/classes/Textmodifier/methods/scale.md @@ -37,5 +37,76 @@ Scale subsequent geometry in model space. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.04; + + const sx = 1 + Math.sin(tm * 1.5) * 0.4; + const sy = 1 + Math.cos(tm * 1.2) * 0.4; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const wave = Math.sin(dist * 0.25 - tm * 2) * Math.cos(x * 0.15 + y * 0.15); + const norm = (wave + 1) * 0.5; + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.scale(sx, sy, 1.0); + t.translate(x, y); + t.charColor(255, Math.floor(140 + sx * 60), Math.floor(100 + sy * 80)); + t.cellColor(Math.floor(8 + norm * 14), Math.floor(12 + norm * 16), Math.floor(28 + norm * 20)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.SCALE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: BREATHING CATHEDRAL LATTICE', x, y++); + t.charColor(140, 160, 190); + t.print('Scales current matrix by scale factors', x, y++); + t.print('along X, Y, and Z coordinate axes.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('TRANSFORM: NON-UNIFORM KINETIC SCALE', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/setCamera.md b/api/textmode.js/classes/Textmodifier/methods/setCamera.md index d6c07d38..d35f4996 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/setCamera.md @@ -32,5 +32,69 @@ Activate a previously created camera object. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let cameraA; +let cameraB; +let active = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + t.perspective(58, 0.1, 4096); + cameraA = t.createCamera(); + cameraA.setPosition(-28, 10, 36).lookAt(0, 0, 0); + cameraB = t.createCamera(); + cameraB.setPosition(28, 10, 36).lookAt(0, 0, 0); +}); + +t.draw(() => { + t.background(6, 8, 18); + active = Math.floor(t.frameCount / 120) % 2 === 0; + t.setCamera(active ? cameraA : cameraB); + t.ambientLight(25, 28, 36); + t.pointLight([255, 210, 140], { x: 18, y: -16, z: 28 }); + for (let i = 0; i < 3; i++) { + t.push(); + t.translate((i - 1) * 9, 0, i * -8); + t.rotateY(t.frameCount + i * 30); + t.char('#'); + t.charColor(120 + i * 40, 220, 255 - i * 20); + t.box(5, 5, 5); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SETCAMERA', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACTIVATE CAMERA', x, y++, 100, 220, 255); + drawText('Two camera objects alternate.', x, y++, 140, 160, 190); + drawText('Scene proves viewpoint change.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(active ? 'ACTIVE: CAMERA A' : 'ACTIVE: CAMERA B', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniform.md b/api/textmode.js/classes/Textmodifier/methods/setUniform.md index b0da768e..ec9519a2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniform.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniform.md @@ -33,5 +33,74 @@ Set a uniform value on the current custom shader. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let customShader = null; + +t.setup(async () => { + customShader = await t.createMaterialShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +uniform vec2 u_mouse; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); + float glyph = step(0.0, wave); + float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); + o_character = vec4(glyph, 0.0, 0.0, 1.0); + o_primaryColor = vec4(0.3, glow, 1.0, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); +}`); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(0); + if (!customShader) return; + t.shader(customShader); + const time = t.frameCount * 0.02; + const mx = (Math.sin(time) + 1) * 0.5; + const my = (Math.cos(time) + 1) * 0.5; + t.setUniform('u_time', time); + t.setUniform('u_mouse', [mx, my]); + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.SETUNIFORM', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); + drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('UNIFORM: u_time', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md index aa73a944..4f8e6f6f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md @@ -32,5 +32,73 @@ Set multiple uniform values on the current custom shader. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let customShader = null; + +t.setup(async () => { + customShader = await t.createMaterialShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +uniform vec2 u_mouse; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); + float glyph = step(0.0, wave); + float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); + o_character = vec4(glyph, 0.0, 0.0, 1.0); + o_primaryColor = vec4(0.3, glow, 1.0, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); +}`); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(0); + if (!customShader) return; + t.shader(customShader); + const time = t.frameCount * 0.02; + const mx = (Math.sin(time) + 1) * 0.5; + const my = (Math.cos(time) + 1) * 0.5; + t.setUniforms({ u_time: time, u_mouse: [mx, my] }); + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.SETUNIFORMS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); + drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('UNIFORMS: 2', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/setup.md b/api/textmode.js/classes/Textmodifier/methods/setup.md index f48e4f7f..3f9edcfa 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setup.md +++ b/api/textmode.js/classes/Textmodifier/methods/setup.md @@ -37,5 +37,59 @@ The callback can be asynchronous (return a Promise). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let seed = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + seed = Math.floor(Math.random() * 999); +}); + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + for (let i = 0; i < 8; i++) { + t.push(); + t.translate(Math.cos(time + i) * 12, Math.sin(time + i) * 6); + t.char(String((seed + i) % 10)); + t.charColor(120 + i * 12, 220, 255 - i * 10); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SETUP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ONE-TIME INIT', x, y++, 100, 220, 255); + drawText('setup() runs before drawing.', x, y++, 140, 160, 190); + drawText('Seed is created once.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SEED: ${seed}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/shader.md b/api/textmode.js/classes/Textmodifier/methods/shader.md index 2a9807ec..06288522 100644 --- a/api/textmode.js/classes/Textmodifier/methods/shader.md +++ b/api/textmode.js/classes/Textmodifier/methods/shader.md @@ -35,5 +35,75 @@ This behavior matches p5.js, allowing multiple draw calls with the same shader. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let customShader = null; + +t.setup(async () => { + customShader = await t.createMaterialShader(`#version 300 es +precision highp float; +in vec2 v_uv; +uniform float u_time; +uniform vec2 u_mouse; +layout(location = 0) out vec4 o_character; +layout(location = 1) out vec4 o_primaryColor; +layout(location = 2) out vec4 o_secondaryColor; +void main() { + float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); + float glyph = step(0.0, wave); + float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); + o_character = vec4(glyph, 0.0, 0.0, 1.0); + o_primaryColor = vec4(0.3, glow, 1.0, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); +}`); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(0); + if (!customShader) return; + t.shader(customShader); + const time = t.frameCount * 0.02; + const mx = (Math.sin(time) + 1) * 0.5; + const my = (Math.cos(time) + 1) * 0.5; + t.setUniform('u_time', time); + t.setUniform('u_mouse', [mx, my]); + t.rect(t.grid.cols, t.grid.rows); + t.resetShader(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.SHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); + drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = customShader ? 'READY' : 'WAIT'; + drawText(`SHADER: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/sin.md b/api/textmode.js/classes/Textmodifier/methods/sin.md index 211d8934..f75ae6f3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sin.md +++ b/api/textmode.js/classes/Textmodifier/methods/sin.md @@ -36,5 +36,72 @@ Sine of the angle. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let phase = 0; +let sample = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(3, 7, 18); + phase = t.frameCount * 0.06; + const width = t.min(54, t.grid.cols - 8); + const amp = t.max(4, t.grid.rows * 0.18); + sample = t.sin(phase); + + for (let x = -t.floor(width / 2); x <= t.floor(width / 2); x++) { + const a = phase + x * 0.28; + const y = t.round(t.sin(a) * amp); + const pulse = t.norm(t.sin(a), -1, 1); + t.push(); + t.translate(x, y); + t.char(pulse > 0.7 ? '*' : pulse > 0.35 ? '+' : '.'); + t.charColor(70 + pulse * 170, 130 + pulse * 100, 255); + t.point(); + t.pop(); + } + + t.char('-'); + t.charColor(55, 75, 115); + t.line(-t.floor(width / 2), 0, t.floor(width / 2), 0); + t.char('@'); + t.charColor(255, 220, 100); + t.push(); + t.translate(0, t.round(sample * amp)); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SIN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SMOOTH OSCILLATION', x, y++, 100, 220, 255); + drawText('sin(angle) flows from -1 to 1.', x, y++, 140, 160, 190); + drawText('The yellow point samples phase.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SIN: ${sample.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/sphere.md b/api/textmode.js/classes/Textmodifier/methods/sphere.md index 4525d984..4082623e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sphere.md +++ b/api/textmode.js/classes/Textmodifier/methods/sphere.md @@ -32,5 +32,61 @@ Draw a sphere mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.sphere(7); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SPHERE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D SPHERE', x, y++, 100, 220, 255); + drawText('Radius defines all axes.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/sq.md b/api/textmode.js/classes/Textmodifier/methods/sq.md index 191c948f..91668208 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sq.md +++ b/api/textmode.js/classes/Textmodifier/methods/sq.md @@ -34,5 +34,67 @@ Value multiplied by itself. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let input = 0; +let squared = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + input = t.sin(t.frameCount * 0.035) * 8 + t.cos(t.frameCount * 0.02) * 2; + squared = t.sq(input); + + for (let x = -12; x <= 12; x++) { + const y = t.round(t.sq(x / 4) - 8); + const hot = t.norm(t.abs(x), 0, 12); + t.push(); + t.translate(x * 2, y); + t.char(hot > 0.7 ? '#' : '+'); + t.charColor(80 + hot * 160, 150, 255 - hot * 90); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(255, 220, 100); + t.push(); + t.translate(t.round(input * 2), t.round(squared / 8 - 8)); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SQ', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PARABOLIC GROWTH', x, y++, 100, 220, 255); + drawText('sq(x) multiplies x by itself.', x, y++, 140, 160, 190); + drawText('Negative and positive both rise.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`X: ${input.toFixed(2)}`, x, y++, 220, 230, 255); + drawText(`SQ: ${squared.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/sqrt.md b/api/textmode.js/classes/Textmodifier/methods/sqrt.md index 3db18219..22391639 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sqrt.md +++ b/api/textmode.js/classes/Textmodifier/methods/sqrt.md @@ -34,5 +34,69 @@ Square root of the value. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let value = 0; +let root = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(3, 8, 16); + value = t.norm(t.sin(t.frameCount * 0.035), -1, 1) * 64 + t.norm(t.cos(t.frameCount * 0.019), -1, 1) * 8; + root = t.sqrt(value); + + for (let i = 0; i < 32; i++) { + const v = i * 2; + const x = -24 + i * 1.5; + const y = 8 - t.sqrt(v) * 2; + const active = v <= value; + t.push(); + t.translate(x, y); + t.char(active ? '#' : '.'); + t.charColor(active ? 110 : 45, active ? 225 : 65, active ? 255 : 95); + t.point(); + t.pop(); + } + + t.char('@'); + t.charColor(255, 220, 100); + t.push(); + t.translate(-24 + value * 0.75, 8 - root * 2); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SQRT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: COMPRESSED GROWTH', x, y++, 100, 220, 255); + drawText('sqrt() grows quickly, then eases.', x, y++, 140, 160, 190); + drawText('The yellow sample climbs slowly.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`VALUE: ${value.toFixed(1)}`, x, y++, 220, 230, 255); + drawText(`SQRT: ${root.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/stroke.md b/api/textmode.js/classes/Textmodifier/methods/stroke.md index 0fef519f..4f7e8a6e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/stroke.md +++ b/api/textmode.js/classes/Textmodifier/methods/stroke.md @@ -30,7 +30,54 @@ Current character color. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); + t.fill(20, 30, 60); + t.stroke(red, 0, 0); + t.char('.'); + t.rect(14, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); + drawText('charColor colors shape edges.', x, y++, 140, 160, 190); + drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -53,7 +100,54 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using a gr ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); + t.fill(20, 30, 60); + t.stroke(red, 0, 0); + t.char('.'); + t.rect(14, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); + drawText('charColor colors shape edges.', x, y++, 140, 160, 190); + drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -82,7 +176,54 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using RGB( ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); + t.fill(20, 30, 60); + t.stroke(red, 0, 0); + t.char('.'); + t.rect(14, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); + drawText('charColor colors shape edges.', x, y++, 140, 160, 190); + drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -104,5 +245,51 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using a CS ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let red = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); + t.fill(20, 30, 60); + t.stroke(red, 0, 0); + t.char('.'); + t.rect(14, 6); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); + drawText('charColor colors shape edges.', x, y++, 140, 160, 190); + drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/swipe.md b/api/textmode.js/classes/Textmodifier/methods/swipe.md index a86e75af..3cc6f2fc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/swipe.md +++ b/api/textmode.js/classes/Textmodifier/methods/swipe.md @@ -35,5 +35,84 @@ per millisecond. Useful for panning, flicks, or quick shortcuts. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const particles = []; +let last = 'NONE'; +let sx = 0; +let sy = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function launch(dx, dy) { + last = Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? 'RIGHT' : 'LEFT') : dy > 0 ? 'DOWN' : 'UP'; + for (let i = 0; i < 8; i++) particles.push({ x: 0, y: 0, vx: dx * (1 + i * 0.1), vy: dy * (1 + i * 0.1), life: 1 }); +} + +t.swipe((data) => { + launch(data.direction.x, data.direction.y); +}); + +t.mousePressed(() => { + sx = t.mouse.x; + sy = t.mouse.y; +}); + +t.mouseReleased(() => { + const dx = t.mouse.x - sx; + const dy = t.mouse.y - sy; + const len = Math.hypot(dx, dy); + if (len > 4) launch(dx / len, dy / len); +}); + +t.draw(() => { + t.background(6, 10, 22); + for (let i = particles.length - 1; i >= 0; i--) { + const p = particles[i]; + p.x += p.vx; + p.y += p.vy; + p.life -= 0.025; + if (p.life <= 0) particles.splice(i, 1); + t.push(); + t.translate(p.x, p.y); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.SWIPE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SWIPE DIRECTION', x, y++, 100, 220, 255); + drawText('Swipe or drag/release.', x, y++, 140, 160, 190); + drawText('Particles follow direction.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('LAST: ' + last, x, y++, 140, 255, 180); + drawText(`ACTIVE: ${particles.length}`, x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/tan.md b/api/textmode.js/classes/Textmodifier/methods/tan.md index 1b34d46c..49b54879 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tan.md +++ b/api/textmode.js/classes/Textmodifier/methods/tan.md @@ -36,5 +36,69 @@ Tangent of the angle. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let angle = 0; +let tangent = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(8, 5, 17); + angle = t.sin(t.frameCount * 0.025) * t.radians(75); + tangent = t.tan(angle); + const slope = t.constrain(tangent, -5, 5); + + t.char('|'); + t.charColor(70, 80, 125); + t.line(-18, -10, -18, 10); + t.line(18, -10, 18, 10); + + for (let x = -18; x <= 18; x++) { + const y = t.round(t.constrain(t.tan(x * 0.08 + angle), -10, 10)); + const heat = t.norm(t.abs(y), 0, 10); + t.push(); + t.translate(x, y); + t.char(heat > 0.75 ? '#' : heat > 0.4 ? '+' : '.'); + t.charColor(90 + heat * 160, 120, 255 - heat * 80); + t.point(); + t.pop(); + } + + t.char('*'); + t.charColor(255, 215, 100); + t.line(-6, t.round(-slope * 3), 6, t.round(slope * 3)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -t.floor(t.grid.cols / 2); + const top = -t.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TAN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SLOPE AND ASYMPTOTES', x, y++, 100, 220, 255); + drawText('tan(angle) grows steep fast.', x, y++, 140, 160, 190); + drawText('Rails show the unstable edges.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TAN: ${tangent.toFixed(2)}`, x, y++, 220, 230, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/tap.md b/api/textmode.js/classes/Textmodifier/methods/tap.md index 1ec1ef22..9f682b6a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tap.md +++ b/api/textmode.js/classes/Textmodifier/methods/tap.md @@ -35,5 +35,76 @@ Use [input.touch.TouchTapEventData.taps](../../../namespaces/input/namespaces/to ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.tap((data) => { + const touch = data?.touch || t.mouse; + addPulse('TAPS', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TAP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TAP GESTURE', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('TAPS: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md index c612632c..0b849bb8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md @@ -36,5 +36,56 @@ Current target frame rate when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let target = 60; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + target = Math.floor(t.frameCount / 150) % 2 === 0 ? 24 : 60; + t.targetFrameRate(target); + for (let i = 0; i < target / 4; i++) { + t.push(); + t.translate(-18 + i, 3); + t.char('+'); + t.charColor(120, 220, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TARGETFRAMERATE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TARGET FPS', x, y++, 100, 220, 255); + drawText('Sets desired draw cadence.', x, y++, 140, 160, 190); + drawText('Readout is kept compact.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TARGET: ${t.targetFrameRate()}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/texture.md b/api/textmode.js/classes/Textmodifier/methods/texture.md index 12c3d948..95614d83 100644 --- a/api/textmode.js/classes/Textmodifier/methods/texture.md +++ b/api/textmode.js/classes/Textmodifier/methods/texture.md @@ -38,7 +38,81 @@ uses source conversion settings such as `characters`, `brightnessRange`, ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const sourceCanvas = document.createElement('canvas'); +sourceCanvas.width = 96; +sourceCanvas.height = 96; +const ctx = sourceCanvas.getContext('2d'); +let source; +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + source = t.createTexture(sourceCanvas); + source.characters(' .:-=+*#%@').cellColorMode('fixed').cellColor(4, 8, 16); +}); + +t.draw(() => { + t.background(4, 7, 18); + if (!ctx || !source) return; + + const hue = (t.frameCount * 2) % 360; + const gradient = ctx.createLinearGradient(0, 0, 96, 96); + gradient.addColorStop(0, `hsl(${hue}, 95%, 58%)`); + gradient.addColorStop(1, `hsl(${(hue + 130) % 360}, 90%, 45%)`); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 96); + ctx.fillStyle = '#ffffff'; + ctx.fillRect(18, 18, 60, 60); + ctx.fillStyle = '#111827'; + ctx.fillRect(30, 30, 36, 36); + + spin = (t.frameCount * 1.2) % 360; + t.perspective(58, 0.1, 4096); + t.camera(0, -8, 34, 0, 0, 0); + t.ambientLight(18, 20, 28); + t.pointLight([255, 230, 180], { x: 20, y: -18, z: 26 }); + t.texture(source); + t.rotateY(spin); + t.rotateX(18); + t.sphere(11); + t.noTexture(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TEXTURED GEOMETRY', x, y++, 100, 220, 255); + drawText('Canvas source samples the sphere.', x, y++, 140, 160, 190); + drawText('Brightness maps to glyphs.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/torus.md b/api/textmode.js/classes/Textmodifier/methods/torus.md index 8c9e718d..9136cf54 100644 --- a/api/textmode.js/classes/Textmodifier/methods/torus.md +++ b/api/textmode.js/classes/Textmodifier/methods/torus.md @@ -33,5 +33,61 @@ Draw a torus mesh primitive. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 40) % 360; + t.perspective(58, 0.1, 4096); + t.camera(18, -10, 42, 0, 0, 0); + t.ambientLight(24, 28, 38); + t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.charColor(140, 220, 255); + t.cellColor(16, 24, 42); + t.torus(8, 2); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TORUS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 3D TORUS', x, y++, 100, 220, 255); + drawText('Major and tube radius define ring.', x, y++, 140, 160, 190); + drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md index 5c9d7a3a..089d1f02 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md @@ -35,5 +35,76 @@ leaves the window. Treat this as an aborted touch and clean up any in-progress s ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.touchCancelled((data) => { + const touch = data?.touch || t.mouse; + addPulse('CANCELS', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TOUCHCANCELLED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TOUCH CANCEL', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CANCELS: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md index cad28248..6814f87a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md @@ -35,5 +35,76 @@ event. Use it to finalise state such as drawing strokes or completing gestures. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.touchEnded((data) => { + const touch = data?.touch || t.mouse; + addPulse('ENDS', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TOUCHENDED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TOUCH END', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ENDS: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md index 5454552b..86588d12 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md @@ -35,5 +35,76 @@ The provided callback is invoked continuously while the browser reports move eve ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.touchMoved((data) => { + const touch = data?.touch || t.mouse; + addPulse('MOVES', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TOUCHMOVED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TOUCH MOVE', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('MOVES: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md index 618393e5..31d165e6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md @@ -36,5 +36,76 @@ more fingers on the canvas. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const pulses = []; +let count = 0; +let last = 'WAITING'; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function addPulse(label, x = 0, y = 0) { + count++; + last = label; + pulses.unshift({ label, x, y, life: 1 }); + if (pulses.length > 12) pulses.length = 12; +} + +t.touchStarted((data) => { + const touch = data?.touch || t.mouse; + addPulse('STARTS', touch?.x || 0, touch?.y || 0); +}); + +t.draw(() => { + t.background(6, 10, 22); + + for (let i = pulses.length - 1; i >= 0; i--) { + const p = pulses[i]; + p.life -= 0.02; + if (p.life <= 0) { + pulses.splice(i, 1); + continue; + } + t.push(); + t.translate(p.x, p.y - (1 - p.life) * 4); + t.char('*'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TOUCHSTARTED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TOUCH BEGIN', x, y++, 100, 220, 255); + drawText('Event updates compact state.', x, y++, 140, 160, 190); + drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STARTS: ' + count, x, y++, 140, 255, 180); + drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/translate.md b/api/textmode.js/classes/Textmodifier/methods/translate.md index d50b9546..24df49a0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translate.md +++ b/api/textmode.js/classes/Textmodifier/methods/translate.md @@ -39,5 +39,58 @@ All geometries are displaced by the specified amounts. Similar to p5.js translat ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let value = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.04; + value = Math.sin(time) * 12; + t.charColor(50, 60, 90); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + t.push(); + t.translate(value, Math.cos(time) * 5, 0); + t.char('#'); + t.charColor(140, 255, 180); + t.rect(6, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRANSLATE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MOVE ORIGIN', x, y++, 100, 220, 255); + drawText('Moves x, y, and z together.', x, y++, 140, 160, 190); + drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`X: ${value.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/translateX.md b/api/textmode.js/classes/Textmodifier/methods/translateX.md index 8345d6c5..3ab5463f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateX.md @@ -30,7 +30,78 @@ Current X-axis translation in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let y = top; y <= bottom; y++) { + const shiftX = Math.sin(tm * 1.8 + y * 0.2) * 8; + + for (let x = left; x <= right; x++) { + const wave = Math.sin((x + shiftX) * 0.25 + tm); + const norm = (wave + 1) * 0.5; + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.translate(0, y); + t.translateX(shiftX); + t.translate(x, 0); + t.charColor(Math.floor(100 + norm * 155), Math.floor(220 - norm * 60), Math.floor(255 - norm * 100)); + t.cellColor(Math.floor(8 + norm * 14), Math.floor(24 + norm * 16), Math.floor(40 + norm * 20)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.TRANSLATEX', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HORIZONTAL SINE WAVE MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('Shifts origin along X-axis independently', x, y++); + t.print('without affecting Y or Z coordinates.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('DISPLACEMENT: FULL-SCREEN X-AXIS WAVE', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -52,5 +123,86 @@ Translate subsequent shapes along the X axis. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let y = top; y <= bottom; y++) { + const shiftA = Math.sin(tm * 1.6 + y * 0.25) * 8; + const shiftB = -shiftA; + + for (let x = left; x <= right; x++) { + const waveA = Math.sin((x + shiftA) * 0.2 + tm); + const normA = (waveA + 1) * 0.5; + + const charKey = RAMP[Math.floor(normA * (RAMP.length - 1))]; + + t.push(); + t.translate(0, y); + t.translateX(shiftA); + t.translate(x, 0); + t.charColor(Math.floor(255 - normA * 80), Math.floor(140 + normA * 100), Math.floor(100 + normA * 120)); + t.cellColor(Math.floor(24 + normA * 14), Math.floor(10 + normA * 12), Math.floor(6 + normA * 10)); + t.char(charKey); + t.point(); + t.pop(); + + t.push(); + t.translate(0, y); + t.translateX(shiftB); + t.translate(x, 0); + t.charColor(Math.floor(100 + normA * 120), Math.floor(240 - normA * 80), Math.floor(180 + normA * 75)); + t.cellColor(Math.floor(6 + normA * 10), Math.floor(20 + normA * 14), Math.floor(12 + normA * 12)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.TRANSLATEX2', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: INTERLOCKING DNA WAVE CURTAIN', x, y++); + t.charColor(140, 160, 190); + t.print('Interlocking double-helix strands', x, y++); + t.print('oscillating horizontally across canvas.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('DISPLACEMENT: PHASED FULL-GRID X SHIFT', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/translateY.md b/api/textmode.js/classes/Textmodifier/methods/translateY.md index 4110f87f..cd8cfa97 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateY.md @@ -30,7 +30,78 @@ Current Y-axis translation in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let x = left; x <= right; x++) { + const shiftY = Math.sin(tm * 2 + x * 0.25) * 6; + + for (let y = top; y <= bottom; y++) { + const wave = Math.cos((y + shiftY) * 0.25 + tm); + const norm = (wave + 1) * 0.5; + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.translate(x, 0); + t.translateY(shiftY); + t.translate(0, y); + t.charColor(255, Math.floor(160 + norm * 95), Math.floor(80 + norm * 120)); + t.cellColor(Math.floor(28 + norm * 14), Math.floor(12 + norm * 12), Math.floor(6 + norm * 10)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.TRANSLATEY', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: EQUALIZER SEISMIC PISTON ARRAY', x, y++); + t.charColor(140, 160, 190); + t.print('Shifts origin along Y-axis independently', x, y++); + t.print('without affecting X or Z coordinates.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('DISPLACEMENT: FULL-SCREEN Y-AXIS PISTONS', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -52,5 +123,75 @@ Translate subsequent shapes along the Y axis. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let x = left; x <= right; x++) { + const dropY = ((tm * 12 + Math.sin(x * 0.4) * 15) % rows) - Math.floor(rows / 2); + + for (let y = top; y <= bottom; y++) { + const distToHead = Math.abs(y - dropY); + const norm = Math.max(0, 1 - distToHead / 8); + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.translate(x, 0); + t.translateY(dropY * 0.1); + t.translate(0, y); + t.charColor(Math.floor(60 + norm * 195), Math.floor(220 + norm * 35), Math.floor(180 - norm * 80)); + t.cellColor(Math.floor(4 + norm * 12), Math.floor(16 + norm * 20), Math.floor(24 + norm * 16)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.TRANSLATEY2', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: DIGITAL RAIN WATERFALL CASCADE', x, y++); + t.charColor(140, 160, 190); + t.print('Vertical offset streams cascading', x, y++); + t.print('downwards through coordinate space.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('DISPLACEMENT: CONTINUOUS Y RAIN STREAM', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/translateZ.md b/api/textmode.js/classes/Textmodifier/methods/translateZ.md index fef25392..b0e43263 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateZ.md @@ -30,7 +30,76 @@ Current Z-axis translation in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-=+*#%@'; + +t.draw(() => { + t.background(6, 10, 24); + const cols = t.grid.cols, + rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2), + right = left + cols - 1; + const top = -Math.floor(rows / 2), + bottom = top + rows - 1; + const tm = t.frameCount * 0.04; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const z = Math.sin(dist * 0.25 - tm * 3) * 16; + const norm = (z + 16) / 32; + + const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; + + t.push(); + t.translateZ(z); + t.translate(x, y); + t.charColor(Math.floor(100 + norm * 155), Math.floor(220 - norm * 80), Math.floor(255 - norm * 120)); + t.cellColor(Math.floor(8 + norm * 16), Math.floor(20 + norm * 18), Math.floor(40 + norm * 20)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3, + x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODIFIER.TRANSLATEZ', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: 3D HYPER-TUNNEL TRAVEL', x, y++); + t.charColor(140, 160, 190); + t.print('Translates origin along Z-axis (depth)', x, y++); + t.print('demonstrating 3D perspective projection.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('DISPLACEMENT: FULL-GRID Z-AXIS WARP', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature @@ -52,5 +121,56 @@ Translate subsequent shapes along the Z axis. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + t.perspective(58, 0.1, 4096); + t.camera(0, 0, 48, 0, 0, 0); + const time = t.frameCount * 0.03; + for (let i = 0; i < 4; i++) { + t.push(); + t.translate((i - 1.5) * 7, 0, 0); + t.translateZ(Math.sin(time + i) * 18); + t.char('#'); + t.charColor(120 + i * 30, 220, 255 - i * 20); + t.box(4, 4, 4); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRANSLATEZ2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DEPTH MOTION', x, y++, 100, 220, 255); + drawText('Boxes move toward camera.', x, y++, 140, 160, 190); + drawText('Z changes perspective scale.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.translateZ(z)', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/triangle.md b/api/textmode.js/classes/Textmodifier/methods/triangle.md index b1951069..6a824ad4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/triangle.md +++ b/api/textmode.js/classes/Textmodifier/methods/triangle.md @@ -43,5 +43,53 @@ Draw a triangle with the current settings. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const time = t.frameCount * 0.03; + t.push(); + t.translate(8, 2); + t.rotateZ(Math.sin(time) * 18); + t.char('^'); + t.charColor(255, 210, 120); + t.cellColor(30, 20, 10); + t.triangle(-9, 6, 0, -7, 9, 6); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: THREE POINT SHAPE', x, y++, 100, 220, 255); + drawText('Uses three explicit vertices.', x, y++, 140, 160, 190); + drawText('Rotation shows the filled area.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('API: t.triangle(...)', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md index e870dbef..64376e63 100644 --- a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md +++ b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md @@ -39,5 +39,51 @@ Current base-layer tileset-color mode when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let authored = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + authored = Math.floor(t.frameCount / 120) % 2 === 0; + t.useTileColors(authored); + t.char(65); + t.charColor(255, 210, 120); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.USETILECOLORS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TILE COLORS', x, y++, 100, 220, 255); + drawText('Toggles authored tile color.', x, y++, 140, 160, 190); + drawText('charColor handles recolor mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(authored ? 'MODE: AUTHORED' : 'MODE: RECOLOR', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/vertex.md b/api/textmode.js/classes/Textmodifier/methods/vertex.md index f45c9af3..bb4f83d8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/vertex.md +++ b/api/textmode.js/classes/Textmodifier/methods/vertex.md @@ -38,5 +38,93 @@ The current transform, character, color, and line state are captured for this ve ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let spin = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function pyramid(size, height) { + const half = size * 0.5; + const top = [0, -height * 0.55, 0]; + const baseY = height * 0.35; + const corners = [ + [-half, baseY, -half], + [half, baseY, -half], + [half, baseY, half], + [-half, baseY, half], + ]; + + t.beginShape(t.TRIANGLES); + for (let i = 0; i < corners.length; i++) { + const next = corners[(i + 1) % corners.length]; + const shade = 120 + i * 32; + t.charColor(shade, 220, 255); + t.vertex(top[0], top[1], top[2]); + t.vertex(corners[i][0], corners[i][1], corners[i][2]); + t.vertex(next[0], next[1], next[2]); + } + + t.charColor(255, 210, 120); + t.vertex(corners[0][0], corners[0][1], corners[0][2]); + t.vertex(corners[1][0], corners[1][1], corners[1][2]); + t.vertex(corners[2][0], corners[2][1], corners[2][2]); + t.vertex(corners[0][0], corners[0][1], corners[0][2]); + t.vertex(corners[2][0], corners[2][1], corners[2][2]); + t.vertex(corners[3][0], corners[3][1], corners[3][2]); + t.endShape(); +} + +t.draw(() => { + t.background(5, 8, 18); + const time = t.frameCount * 0.025; + spin = (time * 42) % 360; + + t.perspective(58, 0.1, 4096); + t.camera(18, -12, 44, 0, 0, 0); + t.ambientLight(18, 24, 34); + t.pointLight([255, 240, 180], { x: 18, y: -20, z: 30 }); + + t.push(); + t.translate(5, 1, 0); + t.rotateY(spin); + t.rotateX(18); + t.char('#'); + t.cellColor(10, 20, 38); + pyramid(14, 12); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BEGINSHAPE2', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CUSTOM 3D MESH', x, y++, 100, 220, 255); + drawText('vertex(x, y, z) builds faces.', x, y++, 140, 160, 190); + drawText('Camera rotation reveals depth.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/methods/windowResized.md b/api/textmode.js/classes/Textmodifier/methods/windowResized.md index 97ca9bd3..a6f74e27 100644 --- a/api/textmode.js/classes/Textmodifier/methods/windowResized.md +++ b/api/textmode.js/classes/Textmodifier/methods/windowResized.md @@ -32,5 +32,53 @@ Set the callback that runs after a window resize. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let resizes = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +window.addEventListener('resize', () => { + resizes++; +}); + +t.draw(() => { + t.background(6, 10, 22); + t.char('#'); + t.charColor(140, 220, 255); + t.rect(12, 5); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.WINDOWRESIZED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RESIZE CALLBACK', x, y++, 100, 220, 255); + drawText('windowResized keeps canvas fit.', x, y++, 140, 160, 190); + drawText('Browser resize updates count.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`RESIZES: ${resizes}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md index c39110f4..17cacc62 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md @@ -26,4 +26,79 @@ that should get brighter as animated layers overlap. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_ADDITIVE; +const modeName = 'BLEND_ADDITIVE'; +const accent = [255, 100, 80]; +const base = [28, 80, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.78 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(4, 8, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.17 + y * 0.11 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : ':'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(2, 6, 16); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 16; i++) { + const angle = i * 22.5 + ring * 11 + t.frameCount * 1.6; + const radius = 4 + ring * 3.8 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '*' : '@'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 10, 12); + t.rect(3, 2 + (i % 2)); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_ADDITIVE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ADDITIVE LIGHT', x, y++, 100, 220, 255); + drawText('Overlaps grow brighter.', x, y++, 140, 160, 190); + drawText('Good for sparks and glow.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md index be235293..4c32372c 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md @@ -26,4 +26,79 @@ shapes that should compress color toward black. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_COLOR_BURN; +const modeName = 'BLEND_COLOR_BURN'; +const accent = [120, 50, 70]; +const base = [220, 170, 110]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.034; + t.background(50, 34, 22); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.13 - y * 0.15 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '%' : '+'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(52, 28, 16); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 18 - t.frameCount * 1.2; + const radius = 5 + ring * 3.8 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '#' : 'X'); + t.charColor(...accent); + t.cellColor(24 + ring * 10, 5, 10 + ring * 6); + t.rect(4, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_COLOR_BURN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: BURN SHADOWS', x, y++, 100, 220, 255); + drawText('Color compresses darker.', x, y++, 140, 160, 190); + drawText('Motion leaves dense marks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md index 737b9037..778a8aed 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md @@ -26,4 +26,79 @@ should push quickly toward white. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_COLOR_DODGE; +const modeName = 'BLEND_COLOR_DODGE'; +const accent = [255, 245, 170]; +const base = [42, 80, 130]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.72 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.038; + t.background(4, 10, 24); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.15 + y * 0.14 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(3, 8, 20); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 19 + t.frameCount * 1.8; + const radius = 4 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '*' : '@'); + t.charColor(...accent); + t.cellColor(45 + ring * 22, 42 + ring * 16, 16); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_COLOR_DODGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DODGE FLARES', x, y++, 100, 220, 255); + drawText('Small marks bloom fast.', x, y++, 140, 160, 190); + drawText('Highlights push to white.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md index 0c637627..37d32c92 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md @@ -26,4 +26,79 @@ existing composition. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_DARKEN; +const modeName = 'BLEND_DARKEN'; +const accent = [90, 110, 170]; +const base = [220, 190, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.03; + t.background(46, 40, 25); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.16 - y * 0.1 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(48, 38, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 19 + t.frameCount; + const radius = 5 + ring * 3.8 + Math.cos(time + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time * 1.5 + i) * 2); + t.char(ring % 2 ? '%' : '#'); + t.charColor(...accent); + t.cellColor(10 + ring * 7, 12 + ring * 8, 30 + ring * 14); + t.rect(4, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_DARKEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DARKER CHANNELS', x, y++, 100, 220, 255); + drawText('Only darker color wins.', x, y++, 140, 160, 190); + drawText('Moving marks add shade.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md index ec4904fb..ad202afc 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md @@ -26,4 +26,79 @@ overlaps that reveal contrast where colors diverge. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_DIFFERENCE; +const modeName = 'BLEND_DIFFERENCE'; +const accent = [255, 255, 255]; +const base = [70, 180, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.9 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.036; + t.background(8, 16, 24); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.17 + y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '-'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(4, 12, 20); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 29 + t.frameCount * 1.5; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '@' : '#'); + t.charColor(...accent); + t.cellColor(70, 70, 70); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_DIFFERENCE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT BY DISTANCE', x, y++, 100, 220, 255); + drawText('Unlike colors spark edges.', x, y++, 140, 160, 190); + drawText('Overlaps flip the field.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md index 2201ece3..d1d66b8e 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md @@ -26,4 +26,79 @@ overlays that should shift color without the full edge of difference. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_EXCLUSION; +const modeName = 'BLEND_EXCLUSION'; +const accent = [230, 230, 255]; +const base = [120, 100, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.033; + t.background(16, 14, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.16 - y * 0.13 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 32, base[2]); + t.cellColor(10, 8, 24); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 25 - t.frameCount * 1.25; + const radius = 5 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(45 + ring * 12, 45 + ring * 12, 68); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_EXCLUSION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOFT INVERSION', x, y++, 100, 220, 255); + drawText('Difference with less bite.', x, y++, 140, 160, 190); + drawText('Color shifts stay muted.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md index a8692632..43170f0a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md @@ -26,4 +26,79 @@ marks that should strongly reshape contrast. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_HARD_LIGHT; +const modeName = 'BLEND_HARD_LIGHT'; +const accent = [255, 220, 70]; +const base = [65, 75, 150]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(10, 12, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.18 - y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '#' : ':'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(8, 8, 24); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 27 - t.frameCount * 1.6; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.4; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? 'X' : '#'); + t.charColor(...accent); + t.cellColor(45 + ring * 20, 38 + ring * 12, 6); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_HARD_LIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HARD CONTRAST', x, y++, 100, 220, 255); + drawText('The top layer drives punch.', x, y++, 140, 160, 190); + drawText('Edges become more graphic.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md index 795681db..1d6cb99b 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md @@ -26,4 +26,79 @@ existing composition. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_LIGHTEN; +const modeName = 'BLEND_LIGHTEN'; +const accent = [255, 230, 130]; +const base = [40, 70, 105]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.034; + t.background(8, 15, 28); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.13 + y * 0.18 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? ':' : '.'); + t.charColor(base[0], base[1] + wave * 25, base[2]); + t.cellColor(5, 10, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 13 - t.frameCount * 1.1; + const radius = 4 + ring * 4 + Math.sin(time + i) * 2.2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time * 1.6 + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(45 + ring * 15, 42 + ring * 10, 18); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_LIGHTEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LIGHTER CHANNELS', x, y++, 100, 220, 255); + drawText('Only brighter color wins.', x, y++, 140, 160, 190); + drawText('Moving marks reveal light.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md index 9414abe9..059dab5f 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md @@ -26,4 +26,79 @@ shadow-like patterns that preserve underlying contrast. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_MULTIPLY; +const modeName = 'BLEND_MULTIPLY'; +const accent = [130, 180, 255]; +const base = [220, 150, 90]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.032; + t.background(42, 30, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.12 - y * 0.16 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '%' : '+'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(50, 28, 12); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 20; i++) { + const angle = i * 18 + ring * 14 - t.frameCount * 1.1; + const radius = 6 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + ring) * 2); + t.char(ring % 2 ? 'X' : '#'); + t.charColor(...accent); + t.cellColor(12, 25 + ring * 20, 58 + ring * 12); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_MULTIPLY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MULTIPLY SHADE', x, y++, 100, 220, 255); + drawText('Overlap darkens the base.', x, y++, 140, 160, 190); + drawText('Color stays tied to below.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md index b548338c..a763dbdd 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md @@ -26,4 +26,80 @@ controlling how much of the layer covers the layers below it. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_NORMAL; +const modeName = 'BLEND_NORMAL'; +const accent = [250, 180, 90]; +const base = [35, 70, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 10, 22); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.18 + y * 0.13 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0] + wave * 30, base[1] + 20, base[2]); + t.cellColor(4, 8, 18); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 17 + t.frameCount * (1.2 + ring * 0.2); + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.rotateZ(-angle * 0.5); + t.char(ring % 2 ? '@' : '#'); + t.charColor(...accent); + t.cellColor(20 + ring * 18, 16, 32 + ring * 12); + t.rect(3 + (i % 2), 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_NORMAL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: NORMAL BLEND', x, y++, 100, 220, 255); + drawText('Animated layer covers below.', x, y++, 140, 160, 190); + drawText('Opacity controls the mix.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md index 7226d4e3..a1906c33 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md @@ -26,4 +26,79 @@ highlights in one pass. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_OVERLAY; +const modeName = 'BLEND_OVERLAY'; +const accent = [255, 90, 190]; +const base = [80, 125, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.83 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.037; + t.background(10, 18, 32); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.14 + y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : '-'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(8, 14, 26); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 21 + t.frameCount * 1.35; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '@' : '%'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 10, 42 + ring * 12); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_OVERLAY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONTRAST BOOST', x, y++, 100, 220, 255); + drawText('Dark stays deep, light lifts.', x, y++, 140, 160, 190); + drawText('Good for graphic masks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md index 93d01621..a5bbe48d 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md @@ -26,4 +26,79 @@ areas while preserving highlight detail. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SCREEN; +const modeName = 'BLEND_SCREEN'; +const accent = [100, 220, 255]; +const base = [85, 45, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.8 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.036; + t.background(12, 8, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.2 + y * 0.08 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(8, 4, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 23 + t.frameCount * 1.3; + const radius = 6 + ring * 3.5 + Math.sin(time + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time * 1.4 + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(5, 30 + ring * 10, 45 + ring * 20); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SCREEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCREEN LIGHT', x, y++, 100, 220, 255); + drawText('Dark areas lift upward.', x, y++, 140, 160, 190); + drawText('Highlights stay open.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md index b6f9af80..f31e0cdc 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md @@ -26,4 +26,79 @@ animated texture that should stay subtle. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SOFT_LIGHT; +const modeName = 'BLEND_SOFT_LIGHT'; +const accent = [255, 170, 150]; +const base = [70, 120, 160]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.029; + t.background(12, 20, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.12 + y * 0.15 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(8, 14, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 16 + t.frameCount * 0.9; + const radius = 5 + ring * 3.5 + Math.sin(time + i) * 1.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '+' : '*'); + t.charColor(...accent); + t.cellColor(28 + ring * 14, 20 + ring * 10, 30); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SOFT_LIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOFT CONTRAST', x, y++, 100, 220, 255); + drawText('Texture changes gently.', x, y++, 140, 160, 190); + drawText('Useful for atmosphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md index 337906a9..17bcf0e9 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md @@ -26,4 +26,79 @@ that remove brightness from the composite. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SUBTRACT; +const modeName = 'BLEND_SUBTRACT'; +const accent = [180, 230, 255]; +const base = [210, 120, 70]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.033; + t.background(48, 28, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.11 + y * 0.19 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : '+'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(55, 24, 10); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 15 - t.frameCount * 1.4; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.8; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '/' : '\\'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 45 + ring * 12, 58); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SUBTRACT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUBTRACT CUTS', x, y++, 100, 220, 255); + drawText('The top layer removes light.', x, y++, 140, 160, 190); + drawText('Bright marks carve paths.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/LINES.md b/api/textmode.js/classes/Textmodifier/properties/LINES.md index c163e2ee..b0aca79a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINES.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINES.md @@ -25,5 +25,59 @@ geometry where every two vertices form a separate edge. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINES; +const modeName = 'LINES'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 8, 22); + t.lineWeight(0.7); + t.beginShape(mode); + for (let i = 0; i < 30; i++) { + const a = i * 12 + t.frameCount * 0.9; + const r1 = 4 + Math.sin(time + i) * 2; + const r2 = 13 + Math.cos(time * 1.7 + i) * 3; + t.char(i % 2 ? '/' : '\\'); + t.charColor(120 + i * 4, 240 - i * 3, 210); + t.vertex(Math.cos(a) * r1, Math.sin(a) * r1); + t.vertex(Math.cos(a + 30) * r2, Math.sin(a + 30) * r2); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PAIRED SEGMENTS', x, y++, 100, 220, 255); + drawText('Every two vertices connect.', x, y++, 140, 160, 190); + drawText('Each pair stays separate.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md index 1fd4ee7b..50805557 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md @@ -25,5 +25,58 @@ the last vertex should connect back to the first. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINE_LOOP; +const modeName = 'LINE_LOOP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(7, 10, 24); + t.lineWeight(0.7); + t.beginShape(mode); + for (let i = 0; i < 64; i++) { + const p = i / 64; + const a = p * Math.PI * 2; + const r = 10 + Math.sin(a * 5 + time * 2) * 2 + Math.cos(a * 3 - time) * 1.5; + t.char(i % 5 === 0 ? '#' : '+'); + t.charColor(120 + Math.sin(a) * 80, 210, 180 + Math.cos(a) * 60); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINE_LOOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLOSED OUTLINE', x, y++, 100, 220, 255); + drawText('Last vertex returns to first.', x, y++, 140, 160, 190); + drawText('Good for orbiting contours.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md index ad6a314b..6b1a1aec 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md @@ -25,5 +25,58 @@ paths that should not automatically close. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINE_STRIP; +const modeName = 'LINE_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(5, 12, 25); + t.lineWeight(0.8); + t.beginShape(mode); + for (let i = 0; i < 70; i++) { + const p = i / 69; + const x = -22 + p * 44; + const y = Math.sin(p * Math.PI * 6 + time * 2) * 5 + Math.sin(p * 19 - time) * 2; + t.char(i % 4 === 0 ? '@' : '~'); + t.charColor(80 + p * 160, 170 + Math.sin(p * 7) * 70, 255); + t.vertex(x, y); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINE_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: OPEN CONTINUOUS PATH', x, y++, 100, 220, 255); + drawText('Consecutive vertices connect.', x, y++, 140, 160, 190); + drawText('The ends remain open.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/POINTS.md b/api/textmode.js/classes/Textmodifier/properties/POINTS.md index 251258db..abae038a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/POINTS.md +++ b/api/textmode.js/classes/Textmodifier/properties/POINTS.md @@ -25,5 +25,57 @@ where every vertex is an independent mark. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.POINTS; +const modeName = 'POINTS'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(6, 10, 24); + t.beginShape(mode); + for (let i = 0; i < 96; i++) { + const a = i * 13.7 + t.frameCount * 1.4; + const r = 2 + i * 0.12 + Math.sin(time * 2 + i) * 1.2; + t.char(i % 3 === 0 ? '*' : '.'); + t.charColor(90 + i, 180 + Math.sin(i) * 50, 255); + t.cellColor(4, 12 + (i % 6) * 5, 30); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POINTS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VERTEX PARTICLES', x, y++, 100, 220, 255); + drawText('Each vertex becomes a point.', x, y++, 140, 160, 190); + drawText('No edges connect the marks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/QUADS.md b/api/textmode.js/classes/Textmodifier/properties/QUADS.md index db89bd9c..ff60cb84 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUADS.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUADS.md @@ -25,5 +25,63 @@ every four vertices define a separate four-sided patch. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.QUADS; +const modeName = 'QUADS'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(6, 10, 20); + t.beginShape(mode); + for (let gy = -2; gy <= 2; gy++) { + for (let gx = -4; gx <= 4; gx++) { + const cx = gx * 4 + Math.sin(time + gy) * 1.5; + const cy = gy * 4 + Math.cos(time + gx) * 1.5; + const s = 1.4 + Math.sin(time * 2 + gx + gy) * 0.5; + t.char((gx + gy) % 2 ? '#' : '+'); + t.charColor(120 + gx * 14, 190 + gy * 12, 250); + t.cellColor(12 + gx * 3, 22 + gy * 6, 45); + t.vertex(cx - s, cy - s); + t.vertex(cx + s, cy - s); + t.vertex(cx + s, cy + s); + t.vertex(cx - s, cy + s); + } + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.QUADS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FOUR VERTEX PATCHES', x, y++, 100, 220, 255); + drawText('Every four vertices fill.', x, y++, 140, 160, 190); + drawText('Each cell is independent.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md index 15e6aa9f..091f09d1 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md @@ -25,5 +25,60 @@ pair of vertices extends the next four-sided segment. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.QUAD_STRIP; +const modeName = 'QUAD_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(8, 8, 24); + t.beginShape(mode); + for (let i = 0; i < 28; i++) { + const p = i / 27; + const x = -20 + p * 40; + const y = Math.sin(p * Math.PI * 4 + time * 2) * 5; + const width = 2 + Math.cos(time + i) * 0.8; + t.char(i % 2 ? '=' : '#'); + t.charColor(255 - p * 80, 140 + p * 90, 210); + t.cellColor(40 + p * 30, 16, 45 + p * 40); + t.vertex(x, y - width); + t.vertex(x, y + width); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.QUAD_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONNECTED QUAD BAND', x, y++, 100, 220, 255); + drawText('Each pair extends the strip.', x, y++, 140, 160, 190); + drawText('Good for thick flowing paths.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md index 1c301f72..c127da26 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md @@ -25,5 +25,61 @@ each triangle controls its own three corners. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLES; +const modeName = 'TRIANGLES'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 8, 20); + t.beginShape(mode); + for (let i = 0; i < 18; i++) { + const a = i * 20 + t.frameCount; + const cx = Math.cos(a) * (5 + (i % 3) * 4); + const cy = Math.sin(a) * (5 + (i % 4) * 2); + const size = 2 + Math.sin(time + i) * 0.8; + t.char(i % 2 ? '^' : '#'); + t.charColor(250, 110 + i * 6, 150 + i * 3); + t.cellColor(40 + i * 4, 10, 25); + t.vertex(cx + Math.cos(a) * size, cy + Math.sin(a) * size); + t.vertex(cx + Math.cos(a + 120) * size, cy + Math.sin(a + 120) * size); + t.vertex(cx + Math.cos(a + 240) * size, cy + Math.sin(a + 240) * size); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INDEPENDENT FACETS', x, y++, 100, 220, 255); + drawText('Every three vertices fill.', x, y++, 140, 160, 190); + drawText('Each triangle stands alone.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md index 07e89a30..b8611658 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md @@ -25,5 +25,62 @@ expanding from a shared center. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLE_FAN; +const modeName = 'TRIANGLE_FAN'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(10, 8, 24); + t.beginShape(mode); + t.char('@'); + t.charColor(255, 245, 180); + t.cellColor(65, 40, 20); + t.vertex(0, 0); + for (let i = 0; i <= 48; i++) { + const p = i / 48; + const a = p * Math.PI * 2 + time; + const r = 12 + Math.sin(a * 6 - time * 3) * 2; + t.char(i % 3 ? '*' : '#'); + t.charColor(255, 130 + Math.sin(a) * 70, 90 + Math.cos(a) * 60); + t.cellColor(55 + Math.sin(a) * 20, 18, 12); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLE_FAN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHARED CENTER', x, y++, 100, 220, 255); + drawText('Every triangle uses vertex 1.', x, y++, 140, 160, 190); + drawText('Great for radial bursts.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md index 323b3d81..3b109ea8 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md @@ -25,5 +25,59 @@ built from a single alternating vertex sequence. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLE_STRIP; +const modeName = 'TRIANGLE_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(5, 12, 26); + t.beginShape(mode); + for (let i = 0; i < 42; i++) { + const p = i / 41; + const x = -20 + p * 40; + const wave = Math.sin(p * Math.PI * 5 + time * 2) * 4; + const side = i % 2 === 0 ? -2.5 : 2.5; + t.char(i % 2 === 0 ? '/' : '\\'); + t.charColor(100 + p * 120, 240 - p * 70, 255); + t.cellColor(8, 28 + p * 40, 45 + p * 70); + t.vertex(x, wave + side); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLE_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONNECTED RIBBON', x, y++, 100, 220, 255); + drawText('Each new vertex adds a face.', x, y++, 140, 160, 190); + drawText('Alternating sides make width.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md index 1fe996fa..575965e8 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md @@ -22,5 +22,77 @@ Physical screen height in pixels. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let displayH = 0; +let ratio = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(8, 9, 20); + displayH = t.displayHeight; + ratio = t.windowHeight / Math.max(1, displayH); + const full = 18; + const visible = Math.round(t.constrain(t.map(ratio, 0, 1, 3, full), 3, full)); + + drawBand(-8, 0, 1, full + 2, 70, 135, 185); + drawBand(8, 0, 1, full + 2, 70, 135, 185); + drawBand(0, -full / 2 - 1, 17, 1, 42, 58, 88); + drawBand(0, full / 2 + 1, 17, 1, 42, 58, 88); + drawBand(0, full / 2 - visible / 2, 11, visible, 62, 120, 165); + + for (let i = 0; i <= full; i += 2) { + const y = full / 2 - i; + const glow = i <= visible; + t.push(); + t.translate(Math.cos(t.frameCount * 0.04 + i) * 4, y); + t.char(glow ? '*' : '.'); + t.charColor(glow ? 255 : 75, glow ? 210 : 95, glow ? 125 : 130); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DISPLAYHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCREEN HEIGHT', x, y++, 100, 220, 255); + drawText('displayHeight reads screen.height.', x, y++, 140, 160, 190); + drawText('Window height is shown inside it.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DISPLAY: ${displayH} PX`, x, y++, 255, 200, 100); + drawText(`WINDOW: ${(ratio * 100).toFixed(0)}%`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md index 5116f67e..5c0dbbcf 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md @@ -22,5 +22,77 @@ Physical screen width in pixels. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let displayW = 0; +let ratio = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(7, 10, 18); + displayW = t.displayWidth; + ratio = t.windowWidth / Math.max(1, displayW); + const full = 30; + const visible = Math.round(t.constrain(t.map(ratio, 0, 1, 3, full), 3, full)); + + drawBand(0, -6, full + 4, 1, 42, 58, 88); + drawBand(0, 6, full + 4, 1, 42, 58, 88); + drawBand(-full / 2 - 2, 0, 1, 13, 70, 135, 185); + drawBand(full / 2 + 2, 0, 1, 13, 70, 135, 185); + drawBand(-full / 2 + visible / 2, 0, visible, 7, 65, 125, 170); + + for (let i = 0; i <= full; i += 3) { + const x = -full / 2 + i; + const glow = i <= visible; + t.push(); + t.translate(x, Math.sin(t.frameCount * 0.04 + i) * 2); + t.char(glow ? '@' : '.'); + t.charColor(glow ? 255 : 80, glow ? 205 : 95, glow ? 120 : 125); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.DISPLAYWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCREEN WIDTH', x, y++, 100, 220, 255); + drawText('displayWidth reads screen.width.', x, y++, 140, 160, 190); + drawText('Window width is shown inside it.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DISPLAY: ${displayW} PX`, x, y++, 255, 200, 100); + drawText(`WINDOW: ${(ratio * 100).toFixed(0)}%`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/gamepads.md b/api/textmode.js/classes/Textmodifier/properties/gamepads.md index 179f48de..6825c12d 100644 --- a/api/textmode.js/classes/Textmodifier/properties/gamepads.md +++ b/api/textmode.js/classes/Textmodifier/properties/gamepads.md @@ -26,5 +26,54 @@ it does not contain sparse `null` holes for disconnected slots. Use ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 6, 12); + const count = Math.max(1, t.gamepads.length); + for (let i = 0; i < 16; i++) { + t.push(); + const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; + t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); + t.char(t.gamepads.length ? '@' : '.'); + t.charColor(80 + i * 8, 180, 255); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODIFIER.GAMEPADS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); + drawText('Works with browser pads.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`PADS: ${t.gamepads.length}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md index 710f1dc7..6dc475f6 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md @@ -22,5 +22,87 @@ Last key pressed, or `null` before any key press. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 18, 22); + + const keyStr = String(t.lastKeyPressed || 'NONE').toUpperCase(); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + + for (let y = -hh; y <= hh; y += 3) { + for (let x = -hw; x <= hw; x += 3) { + const wave = (Math.sin(x * 0.1 + tm) + Math.cos(y * 0.1 - tm)) * 0.5; + if (wave > 0.5) { + t.push(); + t.translate(x, y); + t.charColor(10, 36, 42); + t.char(wave > 0.8 ? '#' : '*'); + t.point(); + t.pop(); + } + } + } + + const pedW = 16, + pedH = 7; + const px = -Math.floor(pedW / 2), + py = -Math.floor(pedH / 2); + + for (let cy = 0; cy < pedH; cy++) { + for (let cx = 0; cx < pedW; cx++) { + const isBorder = cx === 0 || cx === pedW - 1 || cy === 0 || cy === pedH - 1; + t.push(); + t.translate(px + cx, py + cy); + t.cellColor(10, 36, 45); + if (isBorder) { + t.charColor(0, 229, 255); + const isCorner = (cy === 0 || cy === pedH - 1) && (cx === 0 || cx === pedW - 1); + t.char(isCorner ? '+' : cy === 0 || cy === pedH - 1 ? '=' : '|'); + } else { + t.char(' '); + } + t.point(); + t.pop(); + } + } + + t.push(); + t.printAlign('center', 'middle'); + t.charColor(255, 183, 0); + t.print(keyStr.slice(0, 12), 0, 0); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const keyStr = String(t.lastKeyPressed || 'NONE'); + + drawText('TEXTMODIFIER.LASTKEYPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PERSISTENT LAST KEY STATE', x, y++, 100, 220, 255); + drawText('Reads last pressed key property.', x, y++, 140, 160, 190); + drawText('Persists until next key is pressed.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('MEMORY VAULT KEY: ' + keyStr, x, y++, 140, 255, 180); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md index de56d2a8..feae623a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md @@ -22,5 +22,89 @@ Last key released, or `null` before any key release. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 24); + + const keyStr = String(t.lastKeyReleased || 'NONE').toUpperCase(); + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y * 1.3), + echo = (d * 0.25 - tm) % 1.0; + const val = echo < 0 ? echo + 1.0 : echo; + if (val < 0.25) { + const int = 1 - val / 0.25; + t.push(); + t.translate(x, y); + t.charColor(Math.floor(157 + int * 60), Math.floor(78 + int * 90), 223); + t.char(d < 5 ? 'o' : d < 12 ? '*' : '.'); + t.point(); + t.pop(); + } + } + } + + const pedW = 16, + pedH = 5, + px = -8, + py = -2; + for (let cy = 0; cy < pedH; cy++) { + for (let cx = 0; cx < pedW; cx++) { + const isBorder = cx === 0 || cx === pedW - 1 || cy === 0 || cy === pedH - 1; + t.push(); + t.translate(px + cx, py + cy); + t.cellColor(24, 15, 45); + if (isBorder) { + t.charColor(224, 170, 255); + const isCorner = (cy === 0 || cy === pedH - 1) && (cx === 0 || cx === pedW - 1); + t.char(isCorner ? '+' : cy === 0 || cy === pedH - 1 ? '=' : '|'); + } else { + t.char(' '); + } + t.point(); + t.pop(); + } + } + + t.push(); + t.printAlign('center', 'middle'); + t.charColor(255, 204, 255); + t.print(keyStr.slice(0, 12), 0, 0); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const keyStr = String(t.lastKeyReleased || 'NONE'); + + drawText('TEXTMODIFIER.LASTKEYRELEASED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PERSISTENT LAST UP-STROKE', x, y++, 100, 220, 255); + drawText('Reads last released key property.', x, y++, 140, 160, 190); + drawText('Persists until next key is released.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('LAST RELEASED KEY: ' + keyStr, x, y++, 140, 255, 180); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/modifierState.md b/api/textmode.js/classes/Textmodifier/properties/modifierState.md index 914fda52..3f0bebb6 100644 --- a/api/textmode.js/classes/Textmodifier/properties/modifierState.md +++ b/api/textmode.js/classes/Textmodifier/properties/modifierState.md @@ -29,5 +29,57 @@ Current modifier key state. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let active = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + const m = t.modifierState; + active = [m.shift, m.ctrl, m.alt, m.meta].filter(Boolean).length; + ['SHIFT', 'CTRL', 'ALT', 'META'].forEach((name, i) => { + const on = [m.shift, m.ctrl, m.alt, m.meta][i]; + t.push(); + t.translate((i - 1.5) * 7, 0); + t.char(on ? '#' : '.'); + t.charColor(on ? 140 : 80, on ? 255 : 90, 180); + t.rect(5, 3); + t.pop(); + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MODIFIERSTATE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MODIFIER KEYS', x, y++, 100, 220, 255); + drawText('Tracks Shift/Ctrl/Alt/Meta.', x, y++, 140, 160, 190); + drawText('Hold keys to light panels.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ACTIVE: ${active}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/mouse.md b/api/textmode.js/classes/Textmodifier/properties/mouse.md index 1399712f..18ba31a5 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouse.md @@ -33,5 +33,65 @@ it returns `{ x: Number.NEGATIVE_INFINITY, y: Number.NEGATIVE_INFINITY }`. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let mx = 0; +let my = 0; +let inside = false; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + mx = t.mouse.x; + my = t.mouse.y; + inside = mx !== Number.NEGATIVE_INFINITY; + t.charColor(50, 60, 90); + t.char('.'); + t.line(-18, 0, 18, 0); + t.line(0, -10, 0, 10); + if (inside) { + t.push(); + t.translate(mx, my); + t.char('+'); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.MOUSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POINTER POSITION', x, y++, 100, 220, 255); + drawText('Reads current mouse cell position.', x, y++, 140, 160, 190); + drawText('Outside canvas returns infinity.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(inside ? 'INSIDE: TRUE' : 'INSIDE: FALSE', x, y++, 140, 255, 180); + drawText(`X: ${mx}`, x, y++, 180, 200, 220); + drawText(`Y: ${my}`, x, y++, 180, 200, 220); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md index 74fe60c4..e873ca32 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md @@ -26,5 +26,90 @@ starts. Use it inside `draw()` for polling-style interactions. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const RAMP = '+xX#░▒▓█'; +const labelLayer = t.layers.add(); +let pressure = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 5, 10); + const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; + pressure += ((isHeld ? 1.0 : 0.0) - pressure) * 0.12; + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03, + mx = t.mouse.x, + my = t.mouse.y; + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const wave = (Math.sin(x * 0.12 + tm) + Math.cos(y * 0.12 - tm)) * 0.5 + 0.5; + let dispX = x, + dispY = y, + pullFactor = 0; + if (t.mouse.x !== Number.NEGATIVE_INFINITY) { + const dist = Math.hypot(x - mx, y - my); + if (dist < 22) { + pullFactor = Math.pow(1 - dist / 22, 2) * pressure; + dispX = x - (x - mx) * pullFactor * 0.45; + dispY = y - (y - my) * pullFactor * 0.45; + } + } + const intensity = Math.min(1, wave * 0.4 + pullFactor * 0.85); + if (intensity > 0.08) { + const charIdx = Math.min(RAMP.length - 1, Math.floor(intensity * RAMP.length)); + const rx = Math.round(dispX), + ry = Math.round(dispY); + if (rx >= -hw && rx <= hw && ry >= -hh && ry <= hh) { + t.push(); + t.translate(rx, ry); + if (pullFactor > 0.5) { + const h = (pullFactor - 0.5) / 0.5; + t.charColor(255, Math.floor(140 + h * 105), Math.floor(h * 230)); + t.cellColor(Math.floor(120 * h), Math.floor(30 * h), 0); + } else if (pullFactor > 0.15) { + const h = (pullFactor - 0.15) / 0.35; + t.charColor(Math.floor(160 + h * 95), Math.floor(70 + h * 70), Math.floor(30 - h * 30)); + } else { + const b = intensity; + t.charColor(Math.floor(28 + b * 22), Math.floor(45 + b * 37), Math.floor(90 + b * 78)); + } + t.char(RAMP[charIdx]); + t.point(); + t.pop(); + } + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; + drawText('TEXTMODIFIER.MOUSEISPRESSED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SYNCHRONOUS HOLD STATE', x, y++, 100, 220, 255); + drawText('Evaluates boolean state every frame.', x, y++, 140, 160, 190); + drawText('Holding mouse implodes lattice core.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('MOUSE IS PRESSED: ' + (isHeld ? 'TRUE' : 'FALSE'), x, y++, 140, 255, 180); + drawText('PRESSURE INTENSITY: ' + Math.floor(pressure * 100) + '%', x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/movedX.md b/api/textmode.js/classes/Textmodifier/properties/movedX.md index e0822d32..8b3bc2a7 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedX.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedX.md @@ -25,5 +25,97 @@ stop being meaningful and relative movement becomes the primary input signal. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let rotX = 0, + rotY = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (document.pointerLockElement === t.canvas) t.exitPointerLock(); + else t.requestPointerLock(); +}); + +t.draw(() => { + t.background(5, 8, 10); + const isLocked = document.pointerLockElement === t.canvas; + + if (isLocked) { + rotX += t.movedX * 0.35; + rotY += t.movedY * 0.35; + } else { + rotX += 0.25; + } + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const rad = Math.floor(Math.min(hw, hh) * 0.65); + const angleOffset = (rotX * 0.05) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y * 1.4); + const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; + + let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; + let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); + let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; + + if (isRing || isAxis || isTick) { + t.push(); + t.translate(x, y); + + if (isLocked) { + if (d < 3) { + t.charColor(255, 51, 51); + t.cellColor(90, 0, 0); + t.char('+'); + } else if (isTick) { + t.charColor(255, 200, 0); + t.char('#'); + } else { + t.charColor(255, 153, 0); + t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); + } + } else { + t.charColor(68, 85, 102); + t.char(isAxis ? '+' : '.'); + } + + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isLocked = document.pointerLockElement === t.canvas; + + drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); + drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); + drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); + drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); + drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/movedY.md b/api/textmode.js/classes/Textmodifier/properties/movedY.md index 8dea57cd..822e64a1 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedY.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedY.md @@ -25,5 +25,97 @@ stop being meaningful and relative movement becomes the primary input signal. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); +let rotX = 0, + rotY = 0; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.mouseClicked(() => { + if (document.pointerLockElement === t.canvas) t.exitPointerLock(); + else t.requestPointerLock(); +}); + +t.draw(() => { + t.background(5, 8, 10); + const isLocked = document.pointerLockElement === t.canvas; + + if (isLocked) { + rotX += t.movedX * 0.35; + rotY += t.movedY * 0.35; + } else { + rotX += 0.25; + } + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2); + const rad = Math.floor(Math.min(hw, hh) * 0.65); + const angleOffset = (rotX * 0.05) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const d = Math.hypot(x, y * 1.4); + const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; + + let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; + let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); + let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; + + if (isRing || isAxis || isTick) { + t.push(); + t.translate(x, y); + + if (isLocked) { + if (d < 3) { + t.charColor(255, 51, 51); + t.cellColor(90, 0, 0); + t.char('+'); + } else if (isTick) { + t.charColor(255, 200, 0); + t.char('#'); + } else { + t.charColor(255, 153, 0); + t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); + } + } else { + t.charColor(68, 85, 102); + t.char(isAxis ? '+' : '.'); + } + + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isLocked = document.pointerLockElement === t.canvas; + + drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); + drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); + drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); + drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); + drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/pmouse.md b/api/textmode.js/classes/Textmodifier/properties/pmouse.md index d1691008..ea18eb11 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pmouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/pmouse.md @@ -33,5 +33,101 @@ If no previous frame position is available yet, it returns ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(), + trail = []; + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(10, 14, 23); + const mx = t.mouse.x, + my = t.mouse.y, + px = t.pmouse.x, + py = t.pmouse.y; + const isInside = mx !== Number.NEGATIVE_INFINITY && px !== Number.NEGATIVE_INFINITY; + + if (isInside) { + const spd = Math.hypot(mx - px, my - py); + trail.unshift({ x: mx, y: my, speed: spd, life: 1.0 }); + if (trail.length > 35) trail.length = 35; + } + + const hw = Math.floor(t.grid.cols / 2), + hh = Math.floor(t.grid.rows / 2), + tm = t.frameCount * 0.02; + + for (let y = -hh; y <= hh; y += 3) { + for (let x = -hw; x <= hw; x += 3) { + const a = Math.sin(x * 0.08 + tm) + Math.cos(y * 0.08 - tm); + t.push(); + t.translate(x, y); + t.charColor(24, 35, 60); + t.char(a > 0.8 ? '/' : a > 0 ? '|' : a > -0.8 ? '\\' : '-'); + t.point(); + t.pop(); + } + } + + for (let i = trail.length - 1; i >= 0; i--) { + const node = trail[i]; + if ((node.life -= 0.025) <= 0) { + trail.splice(i, 1); + continue; + } + const nx = Math.round(node.x), + ny = Math.round(node.y); + if (nx >= -hw && nx <= hw && ny >= -hh && ny <= hh) { + t.push(); + t.translate(nx, ny); + if (node.speed > 3.0) { + t.charColor(255, 255, 255); + t.cellColor(0, 140, 200); + t.char('█'); + } else if (node.speed > 1.0) { + t.charColor(0, 212, 255); + t.cellColor(0, 50, 80); + t.char('▓'); + } else { + t.charColor(60, 130, 190); + t.char('▒'); + } + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const mx = t.mouse.x, + my = t.mouse.y, + px = t.pmouse.x, + py = t.pmouse.y; + const isInside = mx !== Number.NEGATIVE_INFINITY; + + drawText('TEXTMODIFIER.PMOUSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PREVIOUS POINTER VECTOR', x, y++, 100, 220, 255); + drawText('Reads previous frame coordinates.', x, y++, 140, 160, 190); + drawText('Calculates motion speed & vector stroke.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CURRENT POS: ' + (isInside ? `(${mx}, ${my})` : 'OUTSIDE'), x, y++, 140, 255, 180); + drawText('PREVIOUS POS: ' + (isInside ? `(${px}, ${py})` : 'OUTSIDE'), x, y++, 180, 200, 220); + drawText('MOTION SPEED: ' + (isInside ? Math.hypot(mx - px, my - py).toFixed(2) : '0.00'), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md index 94ccb1f9..3db66763 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md +++ b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md @@ -22,5 +22,96 @@ Keys currently being held down. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const labelLayer = t.layers.add(); + +function drawText(txt, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(txt, x, y); + t.pop(); +} + +t.draw(() => { + t.background(10, 15, 20); + + const activeList = t.pressedKeys || []; + const count = activeList.length; + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + for (let y = -hh + 2; y <= hh - 2; y += 3) { + for (let x = -hw + 2; x <= hw - 2; x += 3) { + const isCross = (x + y) % 6 === 0; + t.push(); + t.translate(x, y); + t.charColor(22, 45, 35); + t.char(isCross ? '+' : '-'); + t.point(); + t.pop(); + } + } + + const numNodes = 12; + const ringRad = 12; + const activeNodes = new Set(); + + for (let i = 0; i < count; i++) { + const key = activeList[i]; + const code = typeof key === 'string' && key.length > 0 ? key.charCodeAt(0) : i; + activeNodes.add(code % numNodes); + } + + for (let i = 0; i < numNodes; i++) { + const ang = (i / numNodes) * Math.PI * 2 + tm; + const nx = Math.round(Math.cos(ang) * ringRad); + const ny = Math.round(Math.sin(ang) * (ringRad * 0.6)); + const isActive = activeNodes.has(i); + + t.push(); + t.translate(nx, ny); + if (isActive) { + t.charColor(255, 42, 95); + t.cellColor(90, 0, 30); + t.char('#'); + } else { + t.charColor(40, 90, 60); + t.char('.'); + } + t.point(); + t.pop(); + } + + if (count > 0) { + t.push(); + t.printAlign('center', 'middle'); + t.charColor(255, 238, 0); + t.print('CHORD: ' + activeList.slice(0, 5).join(' + ').toUpperCase(), 0, 0); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const activeList = t.pressedKeys || []; + + drawText('TEXTMODIFIER.PRESSEDKEYS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MULTI-KEY CHORD POLYPHONY', x, y++, 100, 220, 255); + drawText('Array lists all currently held keys.', x, y++, 140, 160, 190); + drawText('Hold multiple keys to form chords.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('HELD KEY COUNT: ' + activeList.length, x, y++, 140, 255, 180); + drawText('HELD KEYS: ' + activeList.slice(0, 4).join(', '), x, y++, 180, 200, 220); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/touches.md b/api/textmode.js/classes/Textmodifier/properties/touches.md index 9d76be67..ecb39548 100644 --- a/api/textmode.js/classes/Textmodifier/properties/touches.md +++ b/api/textmode.js/classes/Textmodifier/properties/touches.md @@ -25,5 +25,61 @@ available. Use this inside a draw loop to react to active multi-touch scenarios. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let points = []; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + points = Array.from(t.touches); + if (points.length === 0 && t.mouseIsPressed) points = [t.mouse]; + for (let i = 0; i < points.length; i++) { + const p = points[i]; + t.push(); + t.translate(p.x, p.y); + t.char(String(i)); + t.charColor(255, 210, 120); + t.point(); + t.pop(); + if (i > 0) { + t.charColor(80, 120, 180); + t.line(points[i - 1].x, points[i - 1].y, p.x, p.y); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TOUCHES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACTIVE TOUCH LIST', x, y++, 100, 220, 255); + drawText('Shows live touch points.', x, y++, 140, 160, 190); + drawText('Mouse drag acts as fallback.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TOUCHES: ${points.length}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md index 517c07b3..c8bf3975 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md @@ -22,5 +22,81 @@ Current browser window height in pixels. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let winH = 0; +let fill = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(7, 9, 19); + winH = t.windowHeight; + const halfRows = Math.floor(t.grid.rows / 2); + const top = -halfRows + 4; + const bottom = halfRows - 4; + const height = Math.max(6, bottom - top + 1); + const center = (top + bottom) / 2; + fill = t.constrain(Math.round(t.map(winH, 240, Math.max(241, t.displayHeight), 4, height)), 4, height); + + drawBand(-10, center, 1, height, 60, 120, 170); + drawBand(10, center, 1, height, 60, 120, 170); + drawBand(0, top, 21, 1, 42, 58, 92); + drawBand(0, bottom, 21, 1, 42, 58, 92); + drawBand(0, bottom - fill / 2 + 0.5, 1, fill, 125, 245, 185); + + for (let i = 0; i < height; i += 2) { + const y = bottom - i; + const width = Math.round(t.map(Math.cos(i * 0.55 + t.frameCount * 0.05), -1, 1, 3, 14)); + const active = i <= fill; + t.push(); + t.translate(0, y); + t.char(active ? '=' : '-'); + t.charColor(active ? 255 : 60, active ? 175 : 85, active ? 105 : 120); + t.rect(width, 1); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.WINDOWHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VIEWPORT HEIGHT', x, y++, 100, 220, 255); + drawText('windowHeight reads innerHeight live.', x, y++, 140, 160, 190); + drawText('Resize browser to lift the meter.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`HEIGHT: ${winH} PX`, x, y++, 140, 255, 180); + drawText(`CELLS: ${fill}`, x, y++, 255, 210, 120); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md index 104a0e21..6fef24f3 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md @@ -22,5 +22,81 @@ Current browser window width in pixels. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let winW = 0; +let fill = 0; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +function drawBand(x, y, width, height, r, g, b) { + t.push(); + t.translate(x, y); + t.char('█'); + t.charColor(r, g, b); + t.rect(width, height); + t.pop(); +} + +t.draw(() => { + t.background(5, 10, 18); + winW = t.windowWidth; + const halfCols = Math.floor(t.grid.cols / 2); + const left = -halfCols + 4; + const right = halfCols - 4; + const width = Math.max(6, right - left + 1); + const center = (left + right) / 2; + fill = t.constrain(Math.round(t.map(winW, 320, Math.max(321, t.displayWidth), 4, width)), 4, width); + + drawBand(center, -7, width, 1, 40, 55, 85); + drawBand(center, 7, width, 1, 40, 55, 85); + drawBand(left, 0, 1, 15, 75, 145, 190); + drawBand(right, 0, 1, 15, 75, 145, 190); + drawBand(left + fill / 2 - 0.5, 0, fill, 1, 120, 245, 190); + + for (let i = 0; i < width; i += 2) { + const x = left + i; + const height = Math.round(t.map(Math.sin(i * 0.4 + t.frameCount * 0.04), -1, 1, 2, 10)); + const active = i <= fill; + t.push(); + t.translate(x, 0); + t.char(active ? '#' : ':'); + t.charColor(active ? 120 : 45, active ? 220 : 70, active ? 255 : 110); + t.rect(1, height); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.WINDOWWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VIEWPORT WIDTH', x, y++, 100, 220, 255); + drawText('windowWidth reads innerWidth live.', x, y++, 140, 160, 190); + drawText('Resize browser to move the meter.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`WIDTH: ${winW} PX`, x, y++, 140, 255, 180); + drawText(`CELLS: ${fill}`, x, y++, 255, 210, 120); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/textmode.md b/api/textmode.js/classes/textmode.md index c5ee05f0..76b51216 100644 --- a/api/textmode.js/classes/textmode.md +++ b/api/textmode.js/classes/textmode.md @@ -20,7 +20,79 @@ Use it to create [Textmodifier](Textmodifier.md) instances and configure global ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:+*#@'; + +t.draw(() => { + t.background(14, 6, 26); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.02; + + const n = 3 + Math.sin(tm * 0.5) * 1.5; + const m = 2 + Math.cos(tm * 0.7) * 1.5; + + for (let y = -hh; y <= hh; y++) { + const ny = (y / hh) * Math.PI; + for (let x = -hw; x <= hw; x++) { + const nx = (x / hw) * Math.PI; + + const chladni = Math.sin(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.sin(n * ny); + const absVal = Math.abs(chladni); + + if (absVal < 0.6) { + const norm = 1 - absVal / 0.6; + const idx = Math.floor(norm * (RAMP.length - 1)); + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(180 + norm * 75), Math.floor(140 + norm * 70), Math.floor(40 + norm * 50)); + t.cellColor(Math.floor(25 + norm * 20), 8, Math.floor(40 + norm * 20)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODE.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CHLADNI NODAL RESONANCE', x, y++); + t.charColor(140, 160, 190); + t.print('Factory initialization setup.', x, y++); + t.print('Configures canvas & grid context.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 210, 90); + t.print('RESONANCE: ACTIVE', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Accessors diff --git a/api/textmode.js/classes/textmode/accessors/version.md b/api/textmode.js/classes/textmode/accessors/version.md index 9e610741..07e202b4 100644 --- a/api/textmode.js/classes/textmode/accessors/version.md +++ b/api/textmode.js/classes/textmode/accessors/version.md @@ -30,5 +30,99 @@ The package version string. ### Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); + +const v = textmode.version; +const label = t.layers.add(); +const len = v.length; +const PALETTE = [ + [255, 90, 90], + [90, 255, 130], + [90, 180, 255], + [255, 210, 60], + [210, 90, 255], + [60, 240, 220], +]; + +let px = 3; +let py = 2; +let dx = 0.32; +let dy = 0.22; +let ci = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 26); + const C = Math.floor(t.grid.cols / 2); + const R = Math.floor(t.grid.rows / 2); + + for (let x = -C; x <= C; x += 4) + for (let y = -R; y <= R; y += 3) + if ((x * 7 + y * 13) % 19 === 0) { + t.push(); + t.translate(x, y); + t.charColor(18, 26, 52); + t.char('.'); + t.point(); + t.pop(); + } + + px += dx; + py += dy; + + const left = -C; + const top = -R; + let bounced = false; + + if (px < left + 1) { + px = left + 1; + dx = Math.abs(dx); + bounced = true; + } + if (px + len > C - 1) { + px = C - len - 1; + dx = -Math.abs(dx); + bounced = true; + } + if (py < top + 1) { + py = top + 1; + dy = Math.abs(dy); + bounced = true; + } + if (py > R - 2) { + py = R - 2; + dy = -Math.abs(dy); + bounced = true; + } + + if (bounced) ci = (ci + 1) % PALETTE.length; + + t.printAlign('left', 'top'); + t.charColor(PALETTE[ci][0], PALETTE[ci][1], PALETTE[ci][2]); + t.print(v, Math.round(px), Math.round(py)); +}); + +label.draw(() => { + t.clear(); + const L = -Math.floor(t.grid.cols / 2), + T = -Math.floor(t.grid.rows / 2); + let y = T + 3; + drawText('TEXTMODE.VERSION', L + 3, y++, [100, 255, 140]); + drawText('------------------------------------', L + 3, y++, [80, 100, 150]); + drawText('CONCEPT: BOUNCING VERSION', L + 3, y++, [100, 220, 255]); + drawText(`Bounces: ${ci}`, L + 3, y++, [140, 160, 190]); + drawText('------------------------------------', L + 3, y++, [80, 100, 150]); + drawText(`VERSION: ${v}`, L + 3, y++, [140, 255, 180]); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/classes/textmode/methods/create.md b/api/textmode.js/classes/textmode/methods/create.md index b8db4823..fdfe22eb 100644 --- a/api/textmode.js/classes/textmode/methods/create.md +++ b/api/textmode.js/classes/textmode/methods/create.md @@ -34,5 +34,70 @@ The created Textmodifier instance. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = '.+*#%@'; + +t.draw(() => { + t.background(6, 20, 14); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x * 0.8, y); + const ring = (Math.sin(dist * 0.4 - tm) + 1) * 0.5; + const hexPattern = Math.abs(Math.sin(x * 0.3) * Math.cos(y * 0.3)); + + const val = ring * 0.7 + hexPattern * 0.3; + if (val > 0.4) { + const idx = Math.floor(((val - 0.4) / 0.6) * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(Math.floor(40 + val * 180), Math.floor(180 + val * 75), Math.floor(120 + val * 100)); + t.cellColor(4, Math.floor(16 + val * 30), 10); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODE.CREATE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: GENESIS MATRIX WAVEFRONT', x, y++); + t.charColor(140, 160, 190); + t.print('Instantiates a Textmodifier instance.', x, y++); + t.print('Initializes grid resolution & context.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`GRID SIZE: ${t.grid.cols}x${t.grid.rows} CELLS`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/classes/textmode/methods/setErrorLevel.md b/api/textmode.js/classes/textmode/methods/setErrorLevel.md index aaf24a3c..b302addd 100644 --- a/api/textmode.js/classes/textmode/methods/setErrorLevel.md +++ b/api/textmode.js/classes/textmode/methods/setErrorLevel.md @@ -32,5 +32,101 @@ Set the global error handling level for all [Textmodifier](../../Textmodifier.md ## Example - +```javascript +const levels = [ + { name: 'SILENT', value: TextmodeErrorLevel.SILENT, summary: 'no output' }, + { name: 'WARNING', value: TextmodeErrorLevel.WARNING, summary: 'console.warn()' }, + { name: 'ERROR', value: TextmodeErrorLevel.ERROR, summary: 'console.error()' }, + { name: 'THROW', value: TextmodeErrorLevel.THROW, summary: 'throws' }, +]; + +let activeIndex = 1; +textmode.setErrorLevel(levels[activeIndex].value); + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +const rhoPerLevel = [14, 28, 55, 115]; +let state = { x: 1, y: 1, z: 1 }; +const trail = []; + +t.draw(() => { + const cycle = 180; + const idx = Math.floor(t.frameCount / cycle) % levels.length; + + if (idx !== activeIndex) { + activeIndex = idx; + textmode.setErrorLevel(levels[activeIndex].value); + state = { x: 1, y: 1, z: 1 }; + trail.length = 0; + } + + t.background(18, 20, 28); + + const rho = rhoPerLevel[activeIndex]; + const dt = 0.005; + const level = activeIndex / (levels.length - 1); + + for (let s = 0; s < 3; s++) { + state.x += 10 * (state.y - state.x) * dt; + state.y += (state.x * (rho - state.z) - state.y) * dt; + state.z += (state.x * state.y - (state.z * 8) / 3) * dt; + trail.push({ + x: Math.round(state.x * 0.55), + y: Math.round((state.z - rho * 0.6) * 0.55), + }); + } + + if (trail.length > 130) trail.splice(0, trail.length - 130); + + for (let i = 0; i < trail.length; i++) { + const p = trail[i]; + const q = i / trail.length; + + t.push(); + t.translate(p.x, p.y); + t.charColor(60 + level * 195, 180 - level * 140, 80 + level * 175); + t.char(q > 0.7 ? '@' : q > 0.4 ? '+' : '.'); + t.point(); + t.pop(); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const level = levels[activeIndex]; + const meter = levels.map((_, i) => (i <= activeIndex ? '|' : '.')).join(''); + + drawText('TEXTMODE.SETERRORLEVEL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLOBAL ERROR HANDLING', x, y++, 100, 220, 255); + drawText('Sets library diagnostic severity.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ACTIVE LEVEL: ${level.name}`, x, y++, 255, 210, 90); + drawText(`LEVEL METER : ${meter}`, x, y++, 255, 210, 90); + drawText(`BEHAVIOR : ${level.summary}`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/enumerations/ShapeAssemblyMode.md b/api/textmode.js/enumerations/ShapeAssemblyMode.md index 97b105b9..4c9c050c 100644 --- a/api/textmode.js/enumerations/ShapeAssemblyMode.md +++ b/api/textmode.js/enumerations/ShapeAssemblyMode.md @@ -31,7 +31,60 @@ the last vertex should connect back to the first. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINE_LOOP; +const modeName = 'LINE_LOOP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(7, 10, 24); + t.lineWeight(0.7); + t.beginShape(mode); + for (let i = 0; i < 64; i++) { + const p = i / 64; + const a = p * Math.PI * 2; + const r = 10 + Math.sin(a * 5 + time * 2) * 2 + Math.cos(a * 3 - time) * 1.5; + t.char(i % 5 === 0 ? '#' : '+'); + t.charColor(120 + Math.sin(a) * 80, 210, 180 + Math.cos(a) * 60); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINE_LOOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLOSED OUTLINE', x, y++, 100, 220, 255); + drawText('Last vertex returns to first.', x, y++, 140, 160, 190); + drawText('Good for orbiting contours.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -48,7 +101,60 @@ paths that should not automatically close. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINE_STRIP; +const modeName = 'LINE_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(5, 12, 25); + t.lineWeight(0.8); + t.beginShape(mode); + for (let i = 0; i < 70; i++) { + const p = i / 69; + const x = -22 + p * 44; + const y = Math.sin(p * Math.PI * 6 + time * 2) * 5 + Math.sin(p * 19 - time) * 2; + t.char(i % 4 === 0 ? '@' : '~'); + t.charColor(80 + p * 160, 170 + Math.sin(p * 7) * 70, 255); + t.vertex(x, y); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINE_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: OPEN CONTINUOUS PATH', x, y++, 100, 220, 255); + drawText('Consecutive vertices connect.', x, y++, 140, 160, 190); + drawText('The ends remain open.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -65,7 +171,61 @@ geometry where every two vertices form a separate edge. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.LINES; +const modeName = 'LINES'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 8, 22); + t.lineWeight(0.7); + t.beginShape(mode); + for (let i = 0; i < 30; i++) { + const a = i * 12 + t.frameCount * 0.9; + const r1 = 4 + Math.sin(time + i) * 2; + const r2 = 13 + Math.cos(time * 1.7 + i) * 3; + t.char(i % 2 ? '/' : '\\'); + t.charColor(120 + i * 4, 240 - i * 3, 210); + t.vertex(Math.cos(a) * r1, Math.sin(a) * r1); + t.vertex(Math.cos(a + 30) * r2, Math.sin(a + 30) * r2); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.LINES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PAIRED SEGMENTS', x, y++, 100, 220, 255); + drawText('Every two vertices connect.', x, y++, 140, 160, 190); + drawText('Each pair stays separate.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -82,7 +242,59 @@ where every vertex is an independent mark. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.POINTS; +const modeName = 'POINTS'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(6, 10, 24); + t.beginShape(mode); + for (let i = 0; i < 96; i++) { + const a = i * 13.7 + t.frameCount * 1.4; + const r = 2 + i * 0.12 + Math.sin(time * 2 + i) * 1.2; + t.char(i % 3 === 0 ? '*' : '.'); + t.charColor(90 + i, 180 + Math.sin(i) * 50, 255); + t.cellColor(4, 12 + (i % 6) * 5, 30); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.POINTS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VERTEX PARTICLES', x, y++, 100, 220, 255); + drawText('Each vertex becomes a point.', x, y++, 140, 160, 190); + drawText('No edges connect the marks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -99,7 +311,62 @@ pair of vertices extends the next four-sided segment. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.QUAD_STRIP; +const modeName = 'QUAD_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(8, 8, 24); + t.beginShape(mode); + for (let i = 0; i < 28; i++) { + const p = i / 27; + const x = -20 + p * 40; + const y = Math.sin(p * Math.PI * 4 + time * 2) * 5; + const width = 2 + Math.cos(time + i) * 0.8; + t.char(i % 2 ? '=' : '#'); + t.charColor(255 - p * 80, 140 + p * 90, 210); + t.cellColor(40 + p * 30, 16, 45 + p * 40); + t.vertex(x, y - width); + t.vertex(x, y + width); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.QUAD_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONNECTED QUAD BAND', x, y++, 100, 220, 255); + drawText('Each pair extends the strip.', x, y++, 140, 160, 190); + drawText('Good for thick flowing paths.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -116,7 +383,65 @@ every four vertices define a separate four-sided patch. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.QUADS; +const modeName = 'QUADS'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(6, 10, 20); + t.beginShape(mode); + for (let gy = -2; gy <= 2; gy++) { + for (let gx = -4; gx <= 4; gx++) { + const cx = gx * 4 + Math.sin(time + gy) * 1.5; + const cy = gy * 4 + Math.cos(time + gx) * 1.5; + const s = 1.4 + Math.sin(time * 2 + gx + gy) * 0.5; + t.char((gx + gy) % 2 ? '#' : '+'); + t.charColor(120 + gx * 14, 190 + gy * 12, 250); + t.cellColor(12 + gx * 3, 22 + gy * 6, 45); + t.vertex(cx - s, cy - s); + t.vertex(cx + s, cy - s); + t.vertex(cx + s, cy + s); + t.vertex(cx - s, cy + s); + } + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.QUADS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FOUR VERTEX PATCHES', x, y++, 100, 220, 255); + drawText('Every four vertices fill.', x, y++, 140, 160, 190); + drawText('Each cell is independent.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -133,7 +458,64 @@ expanding from a shared center. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLE_FAN; +const modeName = 'TRIANGLE_FAN'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(10, 8, 24); + t.beginShape(mode); + t.char('@'); + t.charColor(255, 245, 180); + t.cellColor(65, 40, 20); + t.vertex(0, 0); + for (let i = 0; i <= 48; i++) { + const p = i / 48; + const a = p * Math.PI * 2 + time; + const r = 12 + Math.sin(a * 6 - time * 3) * 2; + t.char(i % 3 ? '*' : '#'); + t.charColor(255, 130 + Math.sin(a) * 70, 90 + Math.cos(a) * 60); + t.cellColor(55 + Math.sin(a) * 20, 18, 12); + t.vertex(Math.cos(a) * r, Math.sin(a) * r); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLE_FAN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SHARED CENTER', x, y++, 100, 220, 255); + drawText('Every triangle uses vertex 1.', x, y++, 140, 160, 190); + drawText('Great for radial bursts.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -150,7 +532,61 @@ built from a single alternating vertex sequence. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLE_STRIP; +const modeName = 'TRIANGLE_STRIP'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(5, 12, 26); + t.beginShape(mode); + for (let i = 0; i < 42; i++) { + const p = i / 41; + const x = -20 + p * 40; + const wave = Math.sin(p * Math.PI * 5 + time * 2) * 4; + const side = i % 2 === 0 ? -2.5 : 2.5; + t.char(i % 2 === 0 ? '/' : '\\'); + t.charColor(100 + p * 120, 240 - p * 70, 255); + t.cellColor(8, 28 + p * 40, 45 + p * 70); + t.vertex(x, wave + side); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLE_STRIP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONNECTED RIBBON', x, y++, 100, 220, 255); + drawText('Each new vertex adds a face.', x, y++, 140, 160, 190); + drawText('Alternating sides make width.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -167,4 +603,60 @@ each triangle controls its own three corners. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.TRIANGLES; +const modeName = 'TRIANGLES'; +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 8, 20); + t.beginShape(mode); + for (let i = 0; i < 18; i++) { + const a = i * 20 + t.frameCount; + const cx = Math.cos(a) * (5 + (i % 3) * 4); + const cy = Math.sin(a) * (5 + (i % 4) * 2); + const size = 2 + Math.sin(time + i) * 0.8; + t.char(i % 2 ? '^' : '#'); + t.charColor(250, 110 + i * 6, 150 + i * 3); + t.cellColor(40 + i * 4, 10, 25); + t.vertex(cx + Math.cos(a) * size, cy + Math.sin(a) * size); + t.vertex(cx + Math.cos(a + 120) * size, cy + Math.sin(a + 120) * size); + t.vertex(cx + Math.cos(a + 240) * size, cy + Math.sin(a + 240) * size); + } + t.endShape(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.TRIANGLES', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INDEPENDENT FACETS', x, y++, 100, 220, 255); + drawText('Every three vertices fill.', x, y++, 140, 160, 190); + drawText('Each triangle stands alone.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor.md b/api/textmode.js/namespaces/color/classes/TextmodeColor.md index 62fd21b7..16a009ee 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor.md @@ -24,7 +24,92 @@ Use [Textmodifier.color](../../../classes/Textmodifier/methods/color.md) to crea ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 6, 14); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + + const cRgb = t.color(240, 80, 50); + const cHex = t.color('#30E0A0'); + const cGray = t.color(180); + const cRgba = t.color(90, 140, 255, 200); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const manhattan = Math.abs(x) + Math.abs(y); + const chebyshev = Math.max(Math.abs(x), Math.abs(y)); + const ring = Math.floor(manhattan * 0.4 + chebyshev * 0.3 - tm) % 4; + + let col; + if (ring === 0) col = cRgb; + else if (ring === 1) col = cHex; + else if (ring === 2) col = cGray; + else col = cRgba; + + const val = (Math.sin(manhattan * 0.3 - tm) + 1) * 0.5; + if (val > 0.15) { + const idx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); + t.push(); + t.translate(x, y); + t.charColor(col.r, col.g, col.b); + t.cellColor(Math.floor(col.r * 0.12), Math.floor(col.g * 0.12), Math.floor(col.b * 0.12)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const cRgb = t.color(240, 80, 50); + const cHex = t.color('#30E0A0'); + const cGray = t.color(180); + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: COLOR CONSTRUCTOR FORMATS', x, y++); + t.charColor(140, 160, 190); + t.print('Creates instances from RGB, Hex,', x, y++); + t.print('grayscale, and RGBA arguments.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(cRgb.r, cRgb.g, cRgb.b); + t.print(`RGB : t.color(${cRgb.r}, ${cRgb.g}, ${cRgb.b})`, x, y++); + t.charColor(cHex.r, cHex.g, cHex.b); + t.print("HEX : t.color('#30E0A0')", x, y++); + t.charColor(cGray.r, cGray.g, cGray.b); + t.print(`GRAY: t.color(${cGray.r})`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Properties diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md index 3c2d905f..2cf20bd2 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md @@ -33,5 +33,78 @@ A [r, g, b, a] tuple where each component is between 0.0 and 1.0. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const time = t.frameCount * 0.025; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const r = Math.floor((Math.sin(x * 0.12 + time) * 0.5 + 0.5) * 255); + const g = Math.floor((Math.cos(y * 0.14 - time * 0.8) * 0.5 + 0.5) * 255); + const b = Math.floor((Math.sin(x * 0.08 + y * 0.08 + time * 1.4) * 0.5 + 0.5) * 255); + + const col = t.color(r, g, b); + const [nr, ng, nb] = col.normalized; + + const lum = nr * 0.3 + ng * 0.59 + nb * 0.11; + if (lum > 0.25) { + const normLum = (lum - 0.25) / 0.75; + const idx = Math.min(RAMP.length - 1, Math.floor(normLum * RAMP.length)); + + t.push(); + t.translate(x, y); + t.charColor(nr * 255, ng * 255, nb * 255); + t.cellColor(nr * 35, ng * 35, nb * 35); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(255, 128, 64); + const [nr, ng, nb] = sampleCol.normalized; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.NORMALIZED', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: NORMALIZED RGBA CHANNELS', x, y++); + t.charColor(140, 160, 190); + t.print('Returns [0..1] float array for RGBA.', x, y++); + t.print('Drives luminance & cell tinting.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE NORM: [${nr.toFixed(2)}, ${ng.toFixed(2)}, ${nb.toFixed(2)}]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md index 18f1e940..4e0e92e0 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md @@ -31,5 +31,89 @@ A [r, g, b] tuple with values between 0 and 255. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 6, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + + const rx = Math.sin(tm * 1.2) * (hw * 0.6); + const ry = Math.cos(tm * 0.8) * (hh * 0.6); + + const gx = Math.cos(tm * 0.9 + 1.5) * (hw * 0.6); + const gy = Math.sin(tm * 1.3 + 1.5) * (hh * 0.6); + + const bx = Math.sin(tm * 0.7 + 3.0) * (hw * 0.6); + const by = Math.cos(tm * 1.1 + 3.0) * (hh * 0.6); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dr = Math.hypot(x - rx, y - ry); + const dg = Math.hypot(x - gx, y - gy); + const db = Math.hypot(x - bx, y - by); + + const rVal = Math.floor(Math.max(0, 255 - dr * 14)); + const gVal = Math.floor(Math.max(0, 255 - dg * 14)); + const bVal = Math.floor(Math.max(0, 255 - db * 14)); + + const col = t.color(rVal, gVal, bVal); + const [r, g, b] = col.rgb; + + const maxVal = Math.max(r, g, b); + if (maxVal > 30) { + const idx = Math.min(RAMP.length - 1, Math.floor((maxVal / 255) * RAMP.length)); + t.push(); + t.translate(x, y); + t.charColor(r, g, b); + t.cellColor(Math.floor(r * 0.18), Math.floor(g * 0.18), Math.floor(b * 0.18)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(240, 120, 60); + const [r, g, b] = sampleCol.rgb; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.RGB', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: KINETIC RGB LASER WEAVER', x, y++); + t.charColor(140, 160, 190); + t.print('Extracts [r, g, b] tuple array.', x, y++); + t.print('Weaves Lissajous light nodes.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE RGB: [${r}, ${g}, ${b}]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md index d82f5371..9ab11438 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md @@ -31,5 +31,101 @@ A [r, g, b, a] tuple with values between 0 and 255. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const topLayer = t.layers.add({ blendMode: 'normal' }); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(10, 10, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + if ((x + y) % 3 === 0) { + t.push(); + t.translate(x, y); + t.charColor(50, 60, 80); + t.char('.'); + t.point(); + t.pop(); + } + } + } +}); + +topLayer.draw(() => { + t.clear(); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + const d1x = Math.cos(tm) * (hw * 0.3); + const d1y = Math.sin(tm) * (hh * 0.3); + const d2x = Math.cos(tm + 2.1) * (hw * 0.3); + const d2y = Math.sin(tm + 2.1) * (hh * 0.3); + const rad = Math.min(hw, hh) * 0.45; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const in1 = Math.hypot(x - d1x, y - d1y) < rad; + const in2 = Math.hypot(x - d2x, y - d2y) < rad; + if (in1 || in2) { + const col = t.color( + in2 ? 240 : 40, + in1 && in2 ? 220 : in1 ? 200 : 180, + in1 ? 240 : 40, + in1 && in2 ? 220 : 140 + ); + const [cr, cg, cb, ca] = col.rgba; + const idx = Math.min(RAMP.length - 1, Math.floor((ca / 255) * RAMP.length)); + t.push(); + t.translate(x, y); + t.charColor(cr, cg, cb, ca); + t.cellColor(Math.floor(cr * 0.2), Math.floor(cg * 0.2), Math.floor(cb * 0.2), ca); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(40, 200, 240, 140); + const [r, g, b, a] = sampleCol.rgba; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.RGBA', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: OVERLAPPING RGBA DISKS', x, y++); + t.charColor(140, 160, 190); + t.print('Unpacks [r, g, b, a] tuple array.', x, y++); + t.print('Composites translucent orbital lenses.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE RGBA: [${r}, ${g}, ${b}, ${a}]`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md index 31be15c5..27cdfb8c 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md @@ -38,5 +38,58 @@ A new TextmodeColor instance with the updated alpha. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const layers = Array.from({ length: 5 }, () => t.layers.add()); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(0); +}); + +layers.forEach((layer, i) => { + layer.draw(() => { + t.clear(); + + const base = t.color(50, 150, 255); + const opacity = 100 + i * 30; + + t.push(); + t.translate((i - 2) * 5, Math.sin(t.frameCount * 0.05 + i) * 5); + t.charColor(base.withAlpha(opacity)); + t.cellColor(0, 0, 0, 0); + t.char(String.fromCharCode(65 + i)); + t.rect(12, 12); + t.pop(); + }); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODECOLOR.WITHALPHA', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLONE COLOR WITH NEW ALPHA', x, y++, 100, 220, 255); + drawText('Returns copy with adjusted opacity.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Rendering layers A-E with alpha.', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md index 2ea30f41..20209b72 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md @@ -23,5 +23,97 @@ Alpha component (0-255). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const fogLayer = t.layers.add({ blendMode: 'normal' }); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(14, 14, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const gridPattern = Math.abs(x % 4 === 0 || y % 4 === 0 ? 1 : 0); + if (gridPattern) { + t.push(); + t.translate(x, y); + t.charColor(240, 80, 40); + t.cellColor(40, 16, 10); + t.char('+'); + t.point(); + t.pop(); + } + } + } +}); + +fogLayer.draw(() => { + t.clear(); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(x * 0.15 + tm) * Math.cos(y * 0.15 - tm * 0.8); + const alphaVal = Math.floor(Math.max(0, Math.min(255, (wave + 1) * 0.5 * 255))); + + const col = t.color(60, 200, 230, alphaVal); + const a = col.a; + + if (a > 30) { + const idx = Math.floor((a / 255) * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(col.r, col.g, col.b, a); + t.cellColor(10, 40, 50, a); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(60, 200, 230, 180); + const a = sampleCol.a; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.A', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: DISSOLVE FOG MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('Top layer col.a modulates opacity.', x, y++); + t.print('Reveals crimson geometric backdrop.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE ALPHA: ${a} / 255`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md index 1a47b901..a58f5022 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md @@ -23,5 +23,78 @@ Blue component (0-255). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 22); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const d1 = Math.hypot(x - Math.cos(tm) * 8, y - Math.sin(tm) * 6); + const d2 = Math.hypot(x + Math.sin(tm * 0.7) * 8, y + Math.cos(tm * 0.7) * 6); + const wave = (Math.sin(d1 * 0.3 - tm * 1.5) + Math.cos(d2 * 0.3 - tm * 1.2)) * 0.5; + const blueVal = Math.floor(Math.max(0, Math.min(255, (wave * 0.5 + 0.5) * 220 + 35))); + + const col = t.color(15, Math.floor(blueVal * 0.5), blueVal); + const blue = col.b; + + if (blue > 45) { + const norm = (blue - 45) / 210; + const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); + + t.push(); + t.translate(x, y); + t.charColor(col.r, col.g, blue); + t.cellColor(4, 12, Math.floor(blue * 0.25)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(15, 120, 240); + const blue = sampleCol.b; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.B', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: READ BLUE COLOR CHANNEL', x, y++); + t.charColor(140, 160, 190); + t.print('Reads 8-bit blue property (0-255).', x, y++); + t.print('Drives oceanic caustic ripples.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE BLUE: ${blue} / 255`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md index 4b22bebc..50142ed6 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md @@ -23,5 +23,76 @@ Green component (0-255). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 14, 12); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.025; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const lattice = Math.sin((x + y) * 0.2 + tm) * Math.cos((x - y) * 0.2 - tm * 0.7); + const greenVal = Math.floor(Math.max(0, Math.min(255, (lattice * 0.5 + 0.5) * 220 + 35))); + + const col = t.color(20, greenVal, Math.floor(greenVal * 0.35)); + const green = col.g; + + if (green > 50) { + const norm = (green - 50) / 205; + const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); + + t.push(); + t.translate(x, y); + t.charColor(col.r, green, col.b); + t.cellColor(4, Math.floor(green * 0.24), 8); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(20, 220, 80); + const green = sampleCol.g; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.G', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: READ GREEN COLOR CHANNEL', x, y++); + t.charColor(140, 160, 190); + t.print('Reads 8-bit green property (0-255).', x, y++); + t.print('Drives bioluminescent grid density.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE GREEN: ${green} / 255`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md index accb3b1f..45ef4b6f 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md @@ -23,5 +23,81 @@ Red component (0-255). ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(8, 6, 12); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + const fx = Math.cos(tm * 0.8) * (hw * 0.35); + const fy = Math.sin(tm * 0.6) * (hh * 0.35); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const d = Math.hypot(x - fx, y - fy); + const angle = Math.atan2(y - fy, x - fx); + const wave = Math.sin(d * 0.35 - angle * 2 - tm * 2); + const redVal = Math.floor(Math.max(0, Math.min(255, (wave * 0.5 + 0.5) * 230 + 25))); + + const col = t.color(redVal, Math.floor(redVal * 0.25), 30); + const red = col.r; + + if (red > 45) { + const norm = (red - 45) / 210; + const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); + + t.push(); + t.translate(x, y); + t.charColor(red, col.g, col.b); + t.cellColor(Math.floor(red * 0.22), 6, 10); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sampleCol = t.color(240, 60, 30); + const red = sampleCol.r; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODECOLOR.R', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: READ RED COLOR CHANNEL', x, y++); + t.charColor(140, 160, 190); + t.print('Reads 8-bit red property (0-255).', x, y++); + t.print('Drives stellar flare density.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`SAMPLE RED: ${red} / 255`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md index c408ad66..4a9688e9 100644 --- a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md +++ b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md @@ -58,7 +58,99 @@ true if the strategy exists #### Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let hasCustom = false; +let pulseShader = null; + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_uv; + out vec2 v_uv; + void main() { + gl_Position = a_position; + v_uv = a_uv; + } + `; + + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_image; + layout(location = 0) out vec4 o_character; + layout(location = 1) out vec4 o_primaryColor; + layout(location = 2) out vec4 o_secondaryColor; + void main() { + vec4 col = texture(u_image, v_uv); + o_character = vec4(col.r, 0.0, 0.0, 0.0); + o_primaryColor = vec4(col.rgb, 1.0); + o_secondaryColor = vec4(0.0, 0.0, 0.0, 1.0); + } + `; + + pulseShader = await t.createShader(vert, frag); +}); + +t.draw(() => { + t.background(6, 8, 20); + hasCustom = t.conversions.has('custom-mode'); +}); + +t.mouseClicked(() => { + if (hasCustom) { + t.conversions.unregister('custom-mode'); + } else { + t.conversions.register({ + id: 'custom-mode', + createShader: () => pulseShader, + createUniforms: (ctx) => ({ u_image: ctx.source.texture }), + }); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const isDefault = t.conversions.has('brightness'); + + drawText('CONVERSION.HAS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CHECK REGISTERED STRATEGY', x, y++, 100, 220, 255); + drawText('Performs a key lookup in conversions.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`has('brightness') : ${isDefault}`, x, y++, 180, 255, 180); + drawText( + `has('custom-mode'): ${hasCustom}`, + x, + y++, + hasCustom ? 180 : 255, + hasCustom ? 255 : 120, + hasCustom ? 180 : 120 + ); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(hasCustom ? 'Click to unregister.' : 'Click to register custom-mode.', x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + *** @@ -115,5 +207,82 @@ true if the strategy was unregistered, false if it wasn't found #### Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let img = null; +let registered = false; +let customShader = null; + +t.setup(async () => { + const vert = `#version 300 es\nin vec4 a_position; in vec2 a_uv; out vec2 v_uv; void main() { gl_Position = a_position; v_uv = a_uv; }`; + const frag = `#version 300 es\nprecision highp float; in vec2 v_uv; uniform sampler2D u_image; layout(location = 0) out vec4 o_character; layout(location = 1) out vec4 o_primaryColor; layout(location = 2) out vec4 o_secondaryColor; void main() { vec4 col = texture(u_image, v_uv); float greenLuma = col.g; o_character = vec4(greenLuma * 0.8, 0.0, 0.0, 0.0); o_primaryColor = vec4(0.1, 0.9, 0.3, 1.0); o_secondaryColor = vec4(0.01, 0.05, 0.02, 1.0); }`; + + customShader = await t.createShader(vert, frag); + + t.conversions.register({ + id: 'green-custom', + createShader: () => customShader, + createUniforms: (ctx) => ({ u_image: ctx.source.texture }), + }); + + img = await t.loadImage(IMAGE_URL); + img.characters(' .:-=+*#%@'); + img.conversionMode('green-custom'); + registered = true; +}); + +t.draw(() => { + t.background(6, 8, 20); + if (img) { + t.image(img, t.grid.cols - 8, t.grid.rows - 10); + } +}); + +t.mouseClicked(() => { + if (!registered || !img) return; + img.conversionMode('brightness'); + t.conversions.unregister('green-custom'); + registered = false; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const mode = registered ? 'green-custom' : 'brightness'; + + drawText('CONVERSION.UNREGISTER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISPOSE CONVERSION STRATEGY', x, y++, 100, 220, 255); + drawText('Removes registered custom logic.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`ACTIVE MODE: ${mode}`, x, y++, 140, 190, 255); + drawText( + registered ? 'Click to unregister green-custom.' : 'Strategy unregistered successfully.', + x, + y++, + 180, + 255, + 180 + ); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md index 5c1c09ae..21391fd9 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md @@ -50,5 +50,93 @@ brightness range, and character palette texture for the active pass. #### Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let img = null; +let animatedShader = null; + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_uv; + out vec2 v_uv; + void main() { + gl_Position = a_position; + v_uv = a_uv; + } + `; + + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_image; + uniform float u_time; + layout(location = 0) out vec4 o_character; + layout(location = 1) out vec4 o_primaryColor; + layout(location = 2) out vec4 o_secondaryColor; + void main() { + vec4 col = texture(u_image, v_uv); + float wave = 0.5 + 0.5 * sin(u_time + v_uv.x * 12.0); + float luma = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + o_character = vec4(luma * wave * 0.95, 0.0, 0.0, 0.0); + o_primaryColor = vec4(col.r, col.g * wave, col.b * 1.5, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.06, 1.0); + } + `; + + animatedShader = await t.createShader(vert, frag); + + t.conversions.register({ + id: 'time-wave', + createShader: () => animatedShader, + createUniforms: (ctx) => ({ + ...ctx.createBaseUniforms(), + u_time: t.frameCount * 0.04, + }), + }); + + img = await t.loadImage(IMAGE_URL); + img.characters(' .:-=+*#%@'); + img.conversionMode('time-wave'); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (img) { + t.image(img, t.grid.cols - 8, t.grid.rows - 10); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const timeVal = t.frameCount * 0.04; + + drawText('CONVERSION.CREATEUNIFORMS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RENDERING UNIFORMS BINDING', x, y++, 100, 220, 255); + drawText('Binds time-based animation values.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TIME UNIFORM: ${timeVal.toFixed(2)}`, x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md index 87e4ef4b..556fbddc 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md @@ -59,7 +59,88 @@ The compiled GLShader instance. #### Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let img = null; +let blueShader = null; + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_uv; + out vec2 v_uv; + void main() { + gl_Position = a_position; + v_uv = a_uv; + } + `; + + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_image; + layout(location = 0) out vec4 o_character; + layout(location = 1) out vec4 o_primaryColor; + layout(location = 2) out vec4 o_secondaryColor; + void main() { + vec4 col = texture(u_image, v_uv); + float blueLuma = col.b; + o_character = vec4(blueLuma * 0.9, 0.0, 0.0, 0.0); + o_primaryColor = vec4(0.2, 0.6, 1.0, 1.0); + o_secondaryColor = vec4(0.01, 0.03, 0.08, 1.0); + } + `; + + blueShader = await t.createShader(vert, frag); + + t.conversions.register({ + id: 'blue-mrt', + createShader: () => blueShader, + createUniforms: (ctx) => ({ u_image: ctx.source.texture }), + }); + + img = await t.loadImage(IMAGE_URL); + img.characters(' .:-=+*#%@'); + img.conversionMode('blue-mrt'); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (img) { + t.image(img, t.grid.cols - 8, t.grid.rows - 10); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('CONVERSION.CREATESHADER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DYNAMIC SHADER REGISTER', x, y++, 100, 220, 255); + drawText('Outputs custom MRT locations for', x, y++, 140, 160, 190); + drawText('character, primary & secondary.', x, y++, 140, 160, 190); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + *** @@ -88,5 +169,93 @@ An object mapping uniform names to values. #### Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let img = null; +let animatedShader = null; + +t.setup(async () => { + const vert = `#version 300 es + in vec4 a_position; + in vec2 a_uv; + out vec2 v_uv; + void main() { + gl_Position = a_position; + v_uv = a_uv; + } + `; + + const frag = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_image; + uniform float u_time; + layout(location = 0) out vec4 o_character; + layout(location = 1) out vec4 o_primaryColor; + layout(location = 2) out vec4 o_secondaryColor; + void main() { + vec4 col = texture(u_image, v_uv); + float wave = 0.5 + 0.5 * sin(u_time + v_uv.x * 12.0); + float luma = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + o_character = vec4(luma * wave * 0.95, 0.0, 0.0, 0.0); + o_primaryColor = vec4(col.r, col.g * wave, col.b * 1.5, 1.0); + o_secondaryColor = vec4(0.02, 0.03, 0.06, 1.0); + } + `; + + animatedShader = await t.createShader(vert, frag); + + t.conversions.register({ + id: 'time-wave', + createShader: () => animatedShader, + createUniforms: (ctx) => ({ + ...ctx.createBaseUniforms(), + u_time: t.frameCount * 0.04, + }), + }); + + img = await t.loadImage(IMAGE_URL); + img.characters(' .:-=+*#%@'); + img.conversionMode('time-wave'); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (img) { + t.image(img, t.grid.cols - 8, t.grid.rows - 10); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const timeVal = t.frameCount * 0.04; + + drawText('CONVERSION.CREATEUNIFORMS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: RENDERING UNIFORMS BINDING', x, y++, 100, 220, 255); + drawText('Binds time-based animation values.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`TIME UNIFORM: ${timeVal.toFixed(2)}`, x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md index f55d7a92..1e145306 100644 --- a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md +++ b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md @@ -57,7 +57,96 @@ true if the filter exists #### Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let hasCustom = false; + +t.setup(async () => { + const fragment = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_src; + out vec4 outColor; + void main() { + outColor = texture(u_src, v_uv); + } + `; + + await t.filters.register('custom-noop', fragment, {}); +}); + +t.draw(() => { + t.background(6, 9, 20); + + hasCustom = t.filters.has('custom-noop'); + + t.push(); + t.char('#'); + t.rotateZ(t.frameCount * 1.5); + t.charColor(255, 220, 120); + t.rect(12, 12); + t.pop(); +}); + +t.mouseClicked(async () => { + if (hasCustom) { + t.filters.unregister('custom-noop'); + } else { + const fragment = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_src; + out vec4 outColor; + void main() { + outColor = texture(u_src, v_uv); + } + `; + await t.filters.register('custom-noop', fragment, {}); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const isInvert = t.filters.has('invert'); + + drawText('FILTERS.HAS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CHECK REGISTERED FILTER', x, y++, 100, 220, 255); + drawText('Performs lookup in filter registry.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`has('invert') : ${isInvert}`, x, y++, 180, 255, 180); + drawText( + `has('custom-noop'): ${hasCustom}`, + x, + y++, + hasCustom ? 180 : 255, + hasCustom ? 255 : 120, + hasCustom ? 180 : 120 + ); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(hasCustom ? 'Click to unregister.' : 'Click to register custom-noop.', x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + *** @@ -124,5 +213,84 @@ true if the filter was unregistered, false if it wasn't found #### Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); + +const labelLayer = t.layers.add(); +let filterActive = false; + +t.setup(async () => { + const fragment = `#version 300 es + precision highp float; + in vec2 v_uv; + uniform sampler2D u_src; + out vec4 outColor; + void main() { + vec4 col = texture(u_src, v_uv); + outColor = vec4(col.r * 0.1, col.g * 1.5, col.b * 0.2, col.a); + } + `; + + await t.filters.register('green-wash', fragment, {}); + filterActive = true; +}); + +t.draw(() => { + t.background(6, 9, 20); + + t.push(); + t.char('#'); + t.rotateZ(t.frameCount * 1.2); + t.charColor(255, 220, 120); + t.rect(14, 14); + t.pop(); + + if (filterActive && t.filters.has('green-wash')) { + t.filter('green-wash'); + } +}); + +t.mouseClicked(() => { + if (!filterActive) return; + t.filters.unregister('green-wash'); + filterActive = false; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const stateStr = filterActive ? 'ACTIVE' : 'INACTIVE'; + + drawText('FILTERS.UNREGISTER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DISPOSE CUSTOM FILTER', x, y++, 100, 220, 255); + drawText('Removes registered custom shader.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`FILTER STATE: ${stateStr}`, x, y++, 140, 190, 255); + drawText( + filterActive ? 'Click to unregister green-wash.' : 'Filter unregistered successfully.', + x, + y++, + 180, + 255, + 180 + ); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md index 7531d989..4799a7f3 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md @@ -22,7 +22,92 @@ glyph atlas, and used by [layering.TextmodeLayer](../../layering/classes/Textmod ## Example - +```javascript +const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let customFont = null; +let fontReady = false; + +t.setup(async () => { + customFont = await t.loadFont(BESCII_URL); + fontReady = true; +}); + +t.draw(() => { + t.background(6, 14, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const active = fontReady && customFont ? customFont : t.font; + const glyphs = active.characters; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const gridX = Math.abs(x) % 6 === 0; + const gridY = Math.abs(y) % 6 === 0; + const wave = Math.sin(x * 0.2 + y * 0.2 + tm); + const norm = (wave + 1) * 0.5; + + const gIdx = Math.floor((Math.abs(x * y) + tm * 10) % (glyphs.length || 1)); + const glyphObj = glyphs[gIdx] || glyphs[0]; + const char = gridX || gridY ? '+' : glyphObj ? glyphObj.character : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + gridX || gridY ? 255 : Math.floor(40 + norm * 180), + Math.floor(180 + norm * 75), + gridX || gridY ? 180 : Math.floor(220 - norm * 100) + ); + t.cellColor(Math.floor(6 + norm * 12), Math.floor(18 + norm * 20), Math.floor(25 + norm * 25)); + t.char(char); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const status = fontReady ? 'FONT LOADED (BESCII)' : 'LOADING FONT...'; + const glyphCount = fontReady && customFont ? customFont.characters.length : t.font.characters.length; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ASYNC FONT LOADING', x, y++); + t.charColor(140, 160, 190); + t.print('loadFont(url) parses TrueType/WOFF', x, y++); + t.print('and constructs WebGL glyph atlas.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`STATUS: ${status}`, x, y++); + t.print(`GLYPHS LOADED: ${glyphCount}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Extends diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md index 916f618d..509b73c1 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md @@ -29,5 +29,82 @@ Character-to-glyph lookup map. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 10); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.08; + const glyphs = t.font.characters; + const charMap = t.font.characterMap; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const stream = (y + Math.floor(tm * 4 + Math.sin(x * 0.3) * 6)) % (hh * 2 || 1); + const norm = Math.abs(stream) / (hh * 2 || 1); + + const charIdx = Math.floor((Math.abs(x) * 3 + norm * glyphs.length) % glyphs.length); + const charKey = glyphs[charIdx] ? glyphs[charIdx].character : ' '; + + const entry = charMap.get(charKey); + const unicode = entry ? entry.unicode : 32; + + t.push(); + t.translate(x, y); + t.charColor( + Math.floor(40 + (unicode % 180)), + Math.floor(240 - norm * 120), + Math.floor(100 + (unicode % 100)) + ); + t.cellColor(4, Math.floor(14 + norm * 24), 10); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const charMap = t.font.characterMap; + const mapSize = charMap.size; + const sampleEntry = charMap.get('@'); + const hexCode = sampleEntry ? `U+${sampleEntry.unicode.toString(16).toUpperCase().padStart(4, '0')}` : 'N/A'; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.CHARACTERMAP', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CHARACTER MAP LOOKUP', x, y++); + t.charColor(140, 160, 190); + t.print('Maps char strings to glyph metadata.', x, y++); + t.print('O(1) lookup for atlas resolution.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`MAP SIZE: ${mapSize} GLYPHS`, x, y++); + t.print(`GLYPH "@" UNICODE: ${hexCode}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md index 1bc13cbc..54ca2a97 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md @@ -29,5 +29,82 @@ readonly [`TextmodeGlyph`](../../../type-aliases/TextmodeGlyph.md)[] ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(8, 6, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const glyphs = t.font.characters; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const angle = Math.atan2(y, x) + tm; + const radius = Math.hypot(x, y); + const spiral = (angle * 3 + radius * 0.4) % (Math.PI * 2); + const val = (Math.sin(spiral) + 1) * 0.5; + + const gIdx = Math.floor((radius * 2 + angle * 4 + tm * 5) % (glyphs.length || 1)); + const glyphObj = glyphs[gIdx] || glyphs[0]; + const char = glyphObj ? glyphObj.character : '.'; + const unicode = glyphObj ? glyphObj.unicode : 32; + + t.push(); + t.translate(x, y); + t.charColor( + Math.floor(80 + (unicode % 160)), + Math.floor(140 + val * 100), + Math.floor(240 - (unicode % 120)) + ); + t.cellColor(Math.floor(10 + val * 20), Math.floor(12 + val * 20), Math.floor(30 + val * 30)); + t.char(char); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const glyphs = t.font.characters; + const sampleIdx = Math.floor(t.frameCount * 0.05) % (glyphs.length || 1); + const sampleGlyph = glyphs[sampleIdx] || { character: ' ', unicode: 32 }; + const hexCode = `U+${sampleGlyph.unicode.toString(16).toUpperCase().padStart(4, '0')}`; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.CHARACTERS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: UNICODE GLYPH ARRAY', x, y++); + t.charColor(140, 160, 190); + t.print('Array of all font TextmodeGlyph objects.', x, y++); + t.print('Accesses character & unicode attributes.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL GLYPHS: ${glyphs.length}`, x, y++); + t.print(`SAMPLE "${sampleGlyph.character}": ${hexCode}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md index d92a6acc..bf798fc9 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md @@ -32,5 +32,75 @@ when the internal font parser changes. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(8, 10, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const glyphs = t.font.characters; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const chebyshev = Math.max(Math.abs(x), Math.abs(y)); + const wave = Math.sin(chebyshev * 0.4 - tm * 2); + const norm = (wave + 1) * 0.5; + + const angle = Math.atan2(y, x); + const gIdx = Math.floor(Math.abs(chebyshev * 0.8 - tm * 8 + angle * 3) % (glyphs.length || 1)); + const glyphObj = glyphs[gIdx] || glyphs[0]; + const char = glyphObj ? glyphObj.character : '.'; + const unicode = glyphObj ? glyphObj.unicode : 32; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(60 + (unicode % 160)), Math.floor(120 + norm * 120), Math.floor(240 - norm * 100)); + t.cellColor(Math.floor(8 + norm * 15), Math.floor(14 + norm * 20), Math.floor(28 + norm * 25)); + t.char(char); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const fontObj = t.font; + const totalGlyphs = fontObj.characters ? fontObj.characters.length : 0; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.FONT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ACTIVE FONT ACCESSOR', x, y++); + t.charColor(140, 160, 190); + t.print('Gets or sets active TextmodeFont.', x, y++); + t.print('Provides font atlas & glyph data.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL GLYPHS: ${totalGlyphs}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md index 38393dbb..1dd8db93 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md @@ -29,5 +29,74 @@ Font size used for the glyph atlas. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.02; + const glyphs = t.font.characters; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x, y); + const scaleRing = Math.floor(dist * 0.35 - tm * 2) % 5; + const norm = Math.abs(scaleRing) / 5; + + const gIdx = Math.floor(Math.abs(dist * 0.7 - tm * 10 + Math.sin(x * 0.3) * 4) % (glyphs.length || 1)); + const glyphObj = glyphs[gIdx] || glyphs[0]; + const char = glyphObj ? glyphObj.character : '.'; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(240 - norm * 150), Math.floor(160 + norm * 85), Math.floor(60 + norm * 180)); + t.cellColor(Math.floor(10 + norm * 20), Math.floor(18 + norm * 15), Math.floor(30 + norm * 25)); + t.char(char); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const sz = t.font.fontSize; + const dims = t.font.maxGlyphDimensions; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.FONTSIZE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: FONT SIZE METRIC ACCESSOR', x, y++); + t.charColor(140, 160, 190); + t.print('Configures font atlas raster size.', x, y++); + t.print('Determines pixel glyph resolution.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`FONT SIZE: ${sz} PX`, x, y++); + t.print(`CELL DIMS: ${dims.width} x ${dims.height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md index 1ecbdbb5..cb274db1 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md @@ -29,5 +29,77 @@ Normalized glyph atlas framebuffer used by the ASCII shader. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(10, 8, 16); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + + const scanX = Math.sin(tm) * hw; + const scanY = Math.cos(tm * 0.7) * hh; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dBeam1 = Math.abs(x - scanX); + const dBeam2 = Math.abs(y - scanY); + const field = Math.exp(-dBeam1 * 0.2) + Math.exp(-dBeam2 * 0.2); + const norm = Math.min(1, field * 0.5); + + const idx = Math.floor(norm * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(Math.floor(40 + norm * 200), Math.floor(160 + norm * 95), Math.floor(240 - norm * 80)); + t.cellColor(Math.floor(10 + norm * 15), Math.floor(12 + norm * 20), Math.floor(28 + norm * 25)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const fb = t.font.framebuffer; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.FRAMEBUFFER', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ATLAS TEXTURE FRAMEBUFFER', x, y++); + t.charColor(140, 160, 190); + t.print('GLFramebuffer storing glyph atlas.', x, y++); + t.print('Sampled by WebGL ASCII resolve pass.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + if (fb) { + t.print(`ATLAS DIMS: ${fb.width}x${fb.height} PX`, x, y++); + } else { + t.print('ATLAS INITIALIZING...', x, y++); + } + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md index e58be092..5d2772f5 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md @@ -34,5 +34,73 @@ Maximum glyph cell dimensions in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(8, 8, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const dims = t.font.maxGlyphDimensions; + + const boxW = Math.max(3, Math.floor(dims.width / 4)); + const boxH = Math.max(3, Math.floor(dims.height / 4)); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const bx = Math.floor((x + hw) / boxW); + const by = Math.floor((y + hh) / boxH); + const norm = (Math.sin(bx * 0.5 + by * 0.5 + tm) + 1) * 0.5; + + const idx = Math.floor(norm * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(Math.floor(240 - norm * 140), Math.floor(140 + norm * 110), Math.floor(40 + norm * 200)); + t.cellColor(Math.floor(25 - norm * 15), Math.floor(10 + norm * 15), Math.floor(8 + norm * 20)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const dims = t.font.maxGlyphDimensions; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.MAXGLYPHDIMENSIONS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: MAX GLYPH CELL BOUNDS', x, y++); + t.charColor(140, 160, 190); + t.print('Maximum cell bounding dimensions.', x, y++); + t.print('Determines atlas cell slot size.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`MAX DIMS: ${dims.width} x ${dims.height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md index a8c8268e..cec79477 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md @@ -29,5 +29,71 @@ Number of columns in the glyph atlas. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 12, 18); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const texCols = t.font.textureColumns || 16; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const colIndex = Math.abs(x) % texCols; + const normCol = colIndex / texCols; + const wave = Math.sin(colIndex * 0.5 + y * 0.15 + tm); + const norm = (wave + 1) * 0.5; + + const idx = Math.floor(norm * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(Math.floor(40 + normCol * 210), Math.floor(200 - normCol * 100), Math.floor(160 + norm * 80)); + t.cellColor(Math.floor(8 + normCol * 15), Math.floor(20 + norm * 20), Math.floor(30 + normCol * 20)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const texCols = t.font.textureColumns; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.TEXTURECOLUMNS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ATLAS TEXTURE COLUMNS', x, y++); + t.charColor(140, 160, 190); + t.print('Number of horizontal atlas slots.', x, y++); + t.print('Determines atlas UV column layout.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TEXTURE COLUMNS: ${texCols}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md index 16d4dc44..4cb132a6 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md @@ -29,5 +29,71 @@ Number of rows in the glyph atlas. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(16, 6, 12); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + const texRows = t.font.textureRows || 16; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const rowIndex = Math.abs(y) % texRows; + const normRow = rowIndex / texRows; + const wave = Math.cos(rowIndex * 0.5 + x * 0.15 + tm); + const norm = (wave + 1) * 0.5; + + const idx = Math.floor(norm * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(Math.floor(240 - normRow * 100), Math.floor(60 + normRow * 180), Math.floor(160 + norm * 80)); + t.cellColor(Math.floor(24 + normRow * 20), Math.floor(6 + norm * 15), Math.floor(15 + normRow * 15)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const texRows = t.font.textureRows; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.TEXTUREROWS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ATLAS TEXTURE ROWS', x, y++); + t.charColor(140, 160, 190); + t.print('Number of vertical atlas slots.', x, y++); + t.print('Determines atlas UV row layout.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TEXTURE ROWS: ${texRows}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md index d943b660..930c949e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md @@ -27,7 +27,103 @@ Dispose of all resources used by this font manager. ## Example - +```javascript +const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let disposableFont = null; +let fontReady = false; +let isDisposed = false; + +t.setup(async () => { + disposableFont = await t.loadFont(BESCII_URL, false); + fontReady = true; +}); + +t.mousePressed(() => { + if (disposableFont && !isDisposed) { + disposableFont.dispose(); + isDisposed = true; + } +}); + +t.draw(() => { + t.background(16, 6, 10); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + const active = fontReady && !isDisposed && disposableFont ? disposableFont : t.font; + const glyphs = active.characters; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x, y); + const field = isDisposed ? Math.sin(x * 0.4 + y * 0.4 + tm) * 0.2 : Math.sin(dist * 0.3 - tm * 2); + const norm = (field + 1) * 0.5; + + const gIdx = Math.floor(Math.abs(dist * 0.6 + Math.atan2(y, x) * 4 - tm * 8) % (glyphs.length || 1)); + const glyphObj = glyphs[gIdx] || glyphs[0]; + const char = isDisposed ? '.' : glyphObj ? glyphObj.character : ' '; + + t.push(); + t.translate(x, y); + t.charColor( + isDisposed ? 90 : Math.floor(220 - norm * 140), + isDisposed ? 40 : Math.floor(100 + norm * 140), + isDisposed ? 50 : Math.floor(180 + norm * 75) + ); + t.cellColor( + isDisposed ? 18 : Math.floor(20 + norm * 15), + isDisposed ? 6 : Math.floor(6 + norm * 10), + isDisposed ? 8 : Math.floor(12 + norm * 20) + ); + t.char(char); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const stateText = isDisposed ? 'DISPOSED (RELEASED)' : 'ACTIVE (GLYPH ATLAS READY)'; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEFONT.DISPOSE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: FONT RESOURCE CLEANUP', x, y++); + t.charColor(140, 160, 190); + t.print('font.dispose() frees WebGL textures', x, y++); + t.print('and atlas framebuffer memory.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`STATUS: ${stateText}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO DISPOSE FONT', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Overrides diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md index a0338af0..9772d37e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md @@ -25,7 +25,79 @@ The native atlas stays at the authored tile resolution. ## Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const TILE_COLUMNS = 16; +const TILE_ROWS = 16; +const TILE_COUNT = TILE_COLUMNS * TILE_ROWS; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let tileset = null; + +function tilesetOptions() { + return { + source: T64_URL, + columns: TILE_COLUMNS, + rows: TILE_ROWS, + count: TILE_COUNT, + fontSize: 16, + }; +} + +t.setup(async () => { + tileset = await t.loadTileset(tilesetOptions()); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 7, 18); + if (!tileset) return; + const startX = -Math.floor(TILE_COLUMNS / 2); + const startY = -Math.floor(TILE_ROWS / 2); + for (let i = 0; i < TILE_COUNT; i++) { + t.push(); + t.translate(startX + (i % TILE_COLUMNS), startY + Math.floor(i / TILE_COLUMNS)); + t.char(i); + t.charColor(120 + i * 6, 220, 255 - i * 7); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODETILESET.CREATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ATLAS DATA', x, y++, 100, 220, 255); + drawText('T64 web tileset feeds glyphs.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('T64 READY', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Extends diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md index 68804b6d..0d0c2097 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md @@ -34,7 +34,93 @@ Effective tile cell dimensions used by the layer grid. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const RAMP = ' .:-+*#@'; +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(8, 18, 38); + if (!tileset) return; + + const dims = tileset.cellDimensions; + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + + const ratio = dims.width / (dims.height || 1); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.abs(x * ratio) + Math.abs(y); + const ring = (Math.sin(dist * 0.4 - tm) + 1) * 0.5; + + const isCross = x === 0 || y === 0; + + if (ring > 0.45 || isCross) { + const val = isCross ? 1 : (ring - 0.45) / 0.55; + const idx = Math.floor(val * (RAMP.length - 1)); + + t.push(); + t.translate(x, y); + t.charColor( + isCross ? 0 : Math.floor(100 + val * 40), + isCross ? 230 : Math.floor(200 + val * 55), + isCross ? 255 : Math.floor(60 + val * 20) + ); + t.cellColor(4, Math.floor(14 + val * 20), Math.floor(30 + val * 20)); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + if (!tileset) return; + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const d = tileset.cellDimensions; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.CELLDIMENSIONS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: OPTICAL CALIBRATION RETICLE', x, y++); + t.charColor(140, 160, 190); + t.print('Measures tile width & height in px.', x, y++); + t.print('Scales reticle aspect ratio.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 80); + t.print(`TILE DIMS: ${d.width}x${d.height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Combined glyph cell dimensions in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md index 8eacc528..54e525c8 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md @@ -29,7 +29,92 @@ Effective tile cell height used by the layer grid. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(14, 4, 24); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const cH = tileset.cellHeight; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(y * (cH * 0.02) - tm * 2 + Math.sin(x * 0.25) * 2); + const norm = (wave + 1) * 0.5; + + const isCrest = Math.abs(wave) > 0.82; + const charIdx = Math.floor(Math.abs(y * 2 + Math.cos(x * 0.2 + tm * 2) * 6) % (chars.length || 1)); + const charKey = isCrest ? '=' : chars[charIdx] ? chars[charIdx].character : '-'; + + t.push(); + t.translate(x, y); + t.charColor( + isCrest ? 255 : Math.floor(180 + norm * 75), + isCrest ? 200 : Math.floor(40 + norm * 80), + isCrest ? 60 : Math.floor(140 + norm * 80) + ); + t.cellColor( + isCrest ? 35 : Math.floor(8 + norm * 12), + isCrest ? 10 : Math.floor(4 + norm * 10), + isCrest ? 40 : Math.floor(16 + norm * 20) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const height = tileset.cellHeight; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.CELLHEIGHT', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: VERTICAL RASTER OSCILLOGRAM', x, y++); + t.charColor(140, 160, 190); + t.print('Effective render cell height in px.', x, y++); + t.print('Controls vertical wave stride.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 200, 60); + t.print(`CELL HEIGHT: ${height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Height of each glyph cell in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md index fdb3933a..c412ac16 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md @@ -29,7 +29,92 @@ Effective tile cell width used by the layer grid. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(4, 16, 12); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.06; + const chars = tileset.characters; + const cW = tileset.cellWidth; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(x * (cW * 0.01) - tm * 3 + Math.sin(y * 0.25) * 3); + const norm = (wave + 1) * 0.5; + + const isBeam = Math.abs(wave) > 0.85; + const charIdx = Math.floor(Math.abs(x * 2 + Math.cos(y * 0.2 + tm * 3) * 6) % (chars.length || 1)); + const charKey = isBeam ? '=' : chars[charIdx] ? chars[charIdx].character : '-'; + + t.push(); + t.translate(x, y); + t.charColor( + isBeam ? 255 : Math.floor(40 + norm * 180), + isBeam ? 240 : Math.floor(220 - norm * 80), + isBeam ? 120 : Math.floor(140 + norm * 100) + ); + t.cellColor( + isBeam ? 24 : Math.floor(6 + norm * 10), + isBeam ? 35 : Math.floor(20 + norm * 20), + isBeam ? 20 : Math.floor(14 + norm * 15) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const width = tileset.cellWidth; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.CELLWIDTH', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: HORIZON WIDTH PULSE SCANNER', x, y++); + t.charColor(140, 160, 190); + t.print('Effective render cell width in px.', x, y++); + t.print('Controls horizontal column stride.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`CELL WIDTH: ${width} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Width of each glyph cell in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md index ab2fbd88..0ccfff41 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md @@ -29,7 +29,92 @@ Character-to-glyph lookup map for the tileset. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +const KEYS = '@#$%&*<>[]{}~+=-'; +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(4, 8, 6); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.06; + + const map = tileset.characterMap; + + for (let x = -hw; x <= hw; x++) { + const dropSpeed = (Math.abs(x * 17) % 5) + 2; + const dropY = Math.floor((tm * dropSpeed + Math.abs(x * 11)) % (t.grid.rows + 10)) - hh; + + for (let y = -hh; y <= hh; y++) { + const distFromHead = dropY - y; + if (distFromHead >= 0 && distFromHead < 12) { + const charStr = KEYS[Math.abs(x * 3 + y) % KEYS.length]; + const hasMapKey = map ? map.has(charStr) : false; + const isHead = distFromHead === 0; + + t.push(); + t.translate(x, y); + t.charColor( + isHead ? 255 : 80, + isHead ? 255 : Math.floor(220 - distFromHead * 15), + isHead ? 200 : Math.floor(60 - distFromHead * 4) + ); + t.cellColor(4, isHead ? 40 : 12, 8); + t.char(hasMapKey ? charStr : '.'); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + if (!tileset) return; + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const mapSize = tileset.characterMap ? tileset.characterMap.size : 0; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.CHARACTERMAP', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SYMBOLIC CIPHER RAIN', x, y++); + t.charColor(140, 160, 190); + t.print('Queries characterMap key lookups.', x, y++); + t.print('Maps glyph symbols to atlas indices.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(120, 255, 40); + t.print(`MAP SIZE: ${mapSize} ENTRIES`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Lookup table from character string to glyph entry. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md index 085fa249..574e6eca 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md @@ -29,7 +29,98 @@ readonly [`TextmodeGlyph`](../../../type-aliases/TextmodeGlyph.md)[] ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(10, 10, 18); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const chars = tileset.characters; + const cursorIdx = Math.floor(t.frameCount * 0.1) % (chars.length || 1); + + const gridCols = 16; + const gridRows = 16; + const startX = -Math.floor(gridCols / 2); + const startY = -Math.floor(gridRows / 2); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const col = x - startX; + const row = y - startY; + + let charKey = ' '; + let isActive = false; + + if (col >= 0 && col < gridCols && row >= 0 && row < gridRows) { + const tileIndex = row * gridCols + col; + const glyphObj = chars[tileIndex]; + charKey = glyphObj ? glyphObj.character : ' '; + isActive = tileIndex === cursorIdx; + } + + t.push(); + t.translate(x, y); + t.charColor(isActive ? 255 : 120, isActive ? 220 : 180, isActive ? 100 : 240); + t.cellColor(isActive ? 40 : 12, isActive ? 30 : 12, isActive ? 10 : 24); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const chars = tileset.characters; + const cursorIdx = Math.floor(t.frameCount * 0.1) % (chars.length || 1); + const sampleObj = chars[cursorIdx] || { character: ' ', unicode: 32 }; + const hexCode = `U+${sampleObj.unicode.toString(16).toUpperCase().padStart(4, '0')}`; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.CHARACTERS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: FULL TILESET GLYPH CATALOG', x, y++); + t.charColor(140, 160, 190); + t.print('Array of all tileset TextmodeGlyph items.', x, y++); + t.print('Traverses full 256-tile catalog.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`TOTAL TILES: ${chars.length}`, x, y++); + t.print(`ACTIVE TILE: ${hexCode}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Ordered glyph entries available in this atlas. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md index c33dba3f..de9f7430 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md @@ -29,7 +29,93 @@ Number of columns in the normalized glyph atlas. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(4, 18, 26); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const numCols = tileset.columns; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const colIndex = Math.abs(x) % numCols; + const colWave = Math.sin(colIndex * ((Math.PI * 2) / numCols) + tm * 2.5 + Math.cos(y * 0.15) * 1.5); + const norm = (colWave + 1) * 0.5; + + const isPeak = Math.abs(colWave) > 0.85; + const charIdx = Math.floor(Math.abs(colIndex * 16 + y + tm * 10) % (chars.length || 1)); + const charKey = isPeak ? '#' : chars[charIdx] ? chars[charIdx].character : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isPeak ? 255 : Math.floor(20 + norm * 160), + isPeak ? 255 : Math.floor(180 + norm * 75), + isPeak ? 200 : Math.floor(140 + (colIndex / numCols) * 115) + ); + t.cellColor( + isPeak ? 15 : Math.floor(4 + norm * 10), + isPeak ? 45 : Math.floor(16 + norm * 20), + isPeak ? 50 : Math.floor(20 + norm * 25) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const cols = tileset.columns; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.COLUMNS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: 16-CHANNEL SPECTRUM MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('Partitions atlas into column bands.', x, y++); + t.print('Drives column phase offset wave.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(0, 240, 180); + t.print(`ATLAS COLUMNS: ${cols}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Number of glyph columns in the atlas texture. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md index 84a422df..b9a3712d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md @@ -29,5 +29,77 @@ Tileset atlas framebuffer backing this glyph atlas. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const TILE_COLUMNS = 16; +const TILE_ROWS = 16; +const TILE_COUNT = TILE_COLUMNS * TILE_ROWS; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let tileset = null; + +function tilesetOptions() { + return { + source: T64_URL, + columns: TILE_COLUMNS, + rows: TILE_ROWS, + count: TILE_COUNT, + fontSize: 16, + }; +} + +t.setup(async () => { + tileset = await t.loadTileset(tilesetOptions()); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 7, 18); + if (!tileset) return; + const startX = -Math.floor(TILE_COLUMNS / 2); + const startY = -Math.floor(TILE_ROWS / 2); + for (let i = 0; i < TILE_COUNT; i++) { + t.push(); + t.translate(startX + (i % TILE_COLUMNS), startY + Math.floor(i / TILE_COLUMNS)); + t.char(i); + t.charColor(120 + i * 6, 220, 255 - i * 7); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODETILESET.FONTFRAMEBUFFER', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ATLAS DATA', x, y++, 100, 220, 255); + drawText('T64 web tileset feeds glyphs.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const ready = Boolean(tileset.fontFramebuffer); + drawText(`GLYPH ATLAS FRAMEBUFFER: ${ready}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md index ad4e937e..b40ed053 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md @@ -29,5 +29,93 @@ Effective font size used to scale tileset cells. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(6, 6, 16); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + const chars = tileset.characters; + + const cx = -0.7 + Math.sin(tm) * 0.1; + const cy = 0.27015 + Math.cos(tm * 0.7) * 0.05; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + let zx = (x / hw) * 1.5; + let zy = (y / hh) * 1.5; + let iter = 0; + for (let i = 0; i < 16; i++) { + if (zx * zx + zy * zy > 4) break; + const xtemp = zx * zx - zy * zy + cx; + zy = 2 * zx * zy + cy; + zx = xtemp; + iter++; + } + const norm = iter / 16; + + const charIdx = Math.floor(Math.abs(norm * chars.length + tm * 8) % (chars.length || 1)); + const charKey = chars[charIdx] ? chars[charIdx].character : ' '; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(255 - norm * 180), Math.floor(100 + norm * 155), Math.floor(60 + norm * 195)); + t.cellColor(Math.floor(8 + norm * 20), Math.floor(6 + norm * 15), Math.floor(20 + norm * 20)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const sz = tileset.fontSize; + const dims = tileset.cellDimensions; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.FONTSIZE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: JULIA FRACTAL SAMPLING', x, y++); + t.charColor(140, 160, 190); + t.print('Configures output cell render scale.', x, y++); + t.print('Does not alter native source tile size.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`FONT SIZE: ${sz} PX`, x, y++); + t.print(`CELL DIMS: ${dims.width} x ${dims.height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md index 7019b6f6..66833cf3 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md @@ -29,7 +29,98 @@ Normalized glyph atlas framebuffer used by the ASCII shader. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(4, 16, 10); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const sweepAngle = (tm * 2) % (Math.PI * 2); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x, y); + const angle = (Math.atan2(y, x) + Math.PI * 2) % (Math.PI * 2); + const diff = (sweepAngle - angle + Math.PI * 2) % (Math.PI * 2); + + const isRadarLine = diff < 0.15; + const isTrail = diff < 1.2; + const norm = isTrail ? 1 - diff / 1.2 : 0; + + const charIdx = Math.floor(Math.abs(dist * 0.8 + tm * 6) % (chars.length || 1)); + const charKey = isRadarLine ? '@' : isTrail ? (chars[charIdx] ? chars[charIdx].character : '#') : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isRadarLine ? 255 : Math.floor(40 + norm * 180), + isRadarLine ? 255 : Math.floor(100 + norm * 155), + isRadarLine ? 150 : Math.floor(40 + norm * 80) + ); + t.cellColor( + isRadarLine ? 35 : Math.floor(4 + norm * 20), + isRadarLine ? 45 : Math.floor(16 + norm * 24), + isRadarLine ? 20 : Math.floor(10 + norm * 15) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const fb = tileset.framebuffer; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.FRAMEBUFFER', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: REPACKED GPU ATLAS RADAR', x, y++); + t.charColor(140, 160, 190); + t.print('GLFramebuffer containing GPU texture.', x, y++); + t.print('Contains repacked tileset atlas data.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + if (fb) { + t.print(`TEXTURE DIMS: ${fb.width} x ${fb.height} PX`, x, y++); + } + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Framebuffer containing the atlas texture data. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md index 24672fdf..5973dfd5 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md @@ -34,5 +34,90 @@ Effective tile dimensions used by the layer grid. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(8, 24, 48); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const maxDims = tileset.maxGlyphDimensions; + + const boundW = Math.max(3, Math.floor(maxDims.width * 0.6)); + const boundH = Math.max(3, Math.floor(maxDims.height * 0.6)); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const relX = Math.abs(x) % (boundW + 4); + const relY = Math.abs(y) % (boundH + 4); + + const isEdgeX = relX === boundW; + const isEdgeY = relY === boundH; + const isVertex = isEdgeX && isEdgeY; + const isWire = isEdgeX || isEdgeY; + + const charIdx = Math.floor(Math.abs(x * 2 + y * 2 + tm * 6) % (chars.length || 1)); + const charKey = isVertex ? '+' : isWire ? (chars[charIdx] ? chars[charIdx].character : '#') : ' '; + + if (isWire) { + t.push(); + t.translate(x, y); + t.charColor(isVertex ? 255 : 40, isVertex ? 255 : 240, isVertex ? 255 : 140); + t.cellColor(isVertex ? 40 : 12, isVertex ? 50 : 28, isVertex ? 30 : 20); + t.char(charKey); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const maxDims = tileset.maxGlyphDimensions; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.MAXGLYPHDIMENSIONS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CAD CALIPER GRID STAGING', x, y++); + t.charColor(140, 160, 190); + t.print('Bounding box of largest atlas tile.', x, y++); + t.print('Establishes max tile cell bounds.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(40, 240, 140); + t.print(`MAX BOUNDS: ${maxDims.width} x ${maxDims.height} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md index d07a1ae1..21b3041d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md @@ -34,5 +34,92 @@ Authored tile dimensions from the source tileset in pixels. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(10, 10, 16); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const nDims = tileset.nativeCellDimensions; + + const lensX = Math.sin(tm) * 14; + const lensY = Math.cos(tm * 0.7) * 9; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dLens = Math.hypot(x - lensX, y - lensY); + const inLens = dLens < 8; + const isRing = Math.abs(dLens - 8) < 0.8; + + const scale = inLens ? nDims.width / 4 : 1; + const charIdx = Math.floor(Math.abs(x * scale + y * scale + tm * 8) % (chars.length || 1)); + const charKey = isRing ? '+' : chars[charIdx] ? chars[charIdx].character : ' '; + + t.push(); + t.translate(x, y); + t.charColor( + isRing ? 255 : inLens ? 100 : 70, + isRing ? 220 : inLens ? 240 : 120, + isRing ? 100 : inLens ? 180 : 160 + ); + t.cellColor(isRing ? 30 : inLens ? 22 : 8, isRing ? 20 : inLens ? 14 : 6, isRing ? 10 : inLens ? 18 : 10); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const nDims = tileset.nativeCellDimensions; + const cellDims = tileset.cellDimensions; + const scaleFactor = (cellDims.height / (nDims.height || 1)).toFixed(2); + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.NATIVECELLDIMENSIONS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SWEEPING LENS RETICLE PASS', x, y++); + t.charColor(140, 160, 190); + t.print('Native pixel dimensions in source sheet.', x, y++); + t.print('Compared against effective render size.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`NATIVE SIZE : ${nDims.width} x ${nDims.height} PX`, x, y++); + t.print(`SCALE RATIO : ${scaleFactor}X`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md index 6fa69c18..4e618895 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md @@ -29,7 +29,94 @@ Number of rows in the normalized glyph atlas. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(24, 10, 16); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const numRows = tileset.rows; + + for (let y = -hh; y <= hh; y++) { + const rowIndex = Math.abs(y) % numRows; + + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(rowIndex * 0.4 + x * 0.12 - tm * 2); + const norm = (wave + 1) * 0.5; + + const isCrest = Math.abs(wave) > 0.82; + const charIdx = Math.floor(Math.abs(rowIndex * 16 + x + tm * 8) % (chars.length || 1)); + const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isCrest ? 255 : Math.floor(180 + norm * 60), + isCrest ? 210 : Math.floor(90 + norm * 90), + isCrest ? 90 : Math.floor(40 + norm * 60) + ); + t.cellColor( + isCrest ? 45 : Math.floor(12 + norm * 15), + isCrest ? 20 : Math.floor(4 + norm * 10), + isCrest ? 10 : Math.floor(8 + norm * 10) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const numRows = tileset.rows; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.ROWS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: SEISMIC GEOLOGICAL STRATA', x, y++); + t.charColor(140, 160, 190); + t.print('Maps tileset atlas row count.', x, y++); + t.print('Structures horizontal grid strata.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 210, 90); + t.print(`ATLAS ROWS: ${numRows}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + Number of glyph rows in the atlas texture. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md index 21b2a383..dfdbe7fa 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md @@ -29,5 +29,90 @@ Number of columns in the repacked tileset atlas. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(4, 18, 24); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const texCols = tileset.textureColumns; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const colIdx = Math.abs(x) % (texCols || 1); + const ripple = Math.sin(y * 0.2 + colIdx * 0.4 - tm * 2.5); + const norm = (ripple + 1) * 0.5; + + const isCrest = Math.abs(ripple) > 0.85; + const charIdx = Math.floor(Math.abs(colIdx * 16 + y + tm * 8) % (chars.length || 1)); + const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : ':'; + + t.push(); + t.translate(x, y); + t.charColor( + isCrest ? 255 : Math.floor(40 + norm * 180), + isCrest ? 255 : Math.floor(200 - norm * 80), + isCrest ? 180 : Math.floor(60 + (colIdx / texCols) * 120) + ); + t.cellColor( + isCrest ? 20 : Math.floor(4 + norm * 10), + isCrest ? 45 : Math.floor(16 + norm * 20), + isCrest ? 40 : Math.floor(20 + norm * 20) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const texCols = tileset.textureColumns; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.TEXTURECOLUMNS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ATLAS COLUMN STRIDE WAVE', x, y++); + t.charColor(140, 160, 190); + t.print('Horizontal texture column count.', x, y++); + t.print('Defines GPU atlas texture stride.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(0, 255, 180); + t.print(`TEXTURE COLUMNS: ${texCols}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md index d51d948f..4085ab58 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md @@ -29,5 +29,91 @@ Number of rows in the repacked tileset atlas. ### Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let tileset = null; + +t.setup(async () => { + tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); +}); + +t.draw(() => { + t.background(20, 8, 16); + if (!tileset) return; + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const chars = tileset.characters; + const texRows = tileset.textureRows; + + for (let y = -hh; y <= hh; y++) { + const rowIdx = Math.abs(y) % (texRows || 1); + + for (let x = -hw; x <= hw; x++) { + const wave = Math.sin(rowIdx * 0.4 + x * 0.15 - tm * 2); + const norm = (wave + 1) * 0.5; + + const isCrest = Math.abs(wave) > 0.82; + const charIdx = Math.floor(Math.abs(rowIdx * 16 + x + tm * 8) % (chars.length || 1)); + const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isCrest ? 255 : Math.floor(200 + norm * 55), + isCrest ? 220 : Math.floor(80 + norm * 120), + isCrest ? 100 : Math.floor(20 + norm * 40) + ); + t.cellColor( + isCrest ? 45 : Math.floor(14 + norm * 16), + isCrest ? 15 : Math.floor(4 + norm * 10), + isCrest ? 10 : Math.floor(8 + norm * 10) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + if (!tileset) return; + const texRows = tileset.textureRows; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.TEXTUREROWS', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ATLAS ROW STRATA SOUNDING', x, y++); + t.charColor(140, 160, 190); + t.print('Vertical texture row count.', x, y++); + t.print('Defines GPU atlas row structure.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(255, 140, 30); + t.print(`TEXTURE ROWS: ${texRows}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md index 096416f7..c5ce821a 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md @@ -27,7 +27,101 @@ Dispose the tileset and release its shared atlas resources. ## Example - +```javascript +const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let disposableTileset = null; +let fontReady = false; +let isDisposed = false; + +t.setup(async () => { + disposableTileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); + fontReady = true; +}); + +t.mousePressed(() => { + if (disposableTileset && !isDisposed) { + disposableTileset.dispose(); + isDisposed = true; + } +}); + +t.draw(() => { + t.background(16, 6, 10); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.05; + const activeChars = fontReady && !isDisposed && disposableTileset ? disposableTileset.characters : []; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x, y); + const wave = Math.sin(dist * 0.35 - tm * 2); + const norm = (wave + 1) * 0.5; + + const charIdx = Math.floor(Math.abs(dist * 0.6 + tm * 6) % (activeChars.length || 1)); + const glyphObj = activeChars[charIdx]; + const charKey = isDisposed ? '.' : glyphObj ? glyphObj.character : '#'; + + t.push(); + t.translate(x, y); + t.charColor( + isDisposed ? 90 : Math.floor(240 - norm * 140), + isDisposed ? 40 : Math.floor(100 + norm * 140), + isDisposed ? 50 : Math.floor(180 + norm * 75) + ); + t.cellColor( + isDisposed ? 18 : Math.floor(20 + norm * 15), + isDisposed ? 6 : Math.floor(6 + norm * 10), + isDisposed ? 8 : Math.floor(12 + norm * 20) + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const stateText = isDisposed ? 'DISPOSED (GPU MEMORY FREED)' : 'ACTIVE (GLYPH ATLAS READY)'; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODETILESET.DISPOSE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: GPU ATLAS DISSOLVE MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('tileset.dispose() releases WebGL GPU', x, y++); + t.print('textures and atlas framebuffer.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`STATUS: ${stateText}`, x, y++); + t.charColor(255, 200, 100); + t.print('CLICK CANVAS TO DISPOSE TILESET', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Overrides diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md index 22820d4a..97517780 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md @@ -32,5 +32,66 @@ Framebuffer containing this layer's rendered textmode output. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const layer = t.layers.add({ blendMode: 'screen' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.translate(x, y); + t.charColor(rgb[0], rgb[1], rgb[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +layer.draw(() => { + t.clear(); + t.push(); + t.rotateZ(t.frameCount * 2); + t.char('*'); + t.charColor(120, 220, 255); + t.rect(14, 8); + t.pop(); +}); + +t.draw(() => { + t.background(8, 10, 18); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const fb = layer.asciiFramebuffer; + + drawText('TEXTMODELAYER.ASCIIFRAMEBUFFER', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: READ ASCII OUTPUT', x, y++, [100, 220, 255]); + drawText('Samples the converted texture.', x, y++, [140, 160, 190]); + drawText('Center pixel updates each frame.', x, y++, [140, 160, 190]); + if (!fb) return; + + const pixels = fb.readPixels(0); + const index = (Math.floor(fb.height / 2) * fb.width + Math.floor(fb.width / 2)) * 4; + const rgb = `${pixels[index]}, ${pixels[index + 1]}, ${pixels[index + 2]}`; + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`RGB: ${rgb}`, x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md index 53f5250e..bb24f72b 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md @@ -34,5 +34,77 @@ Returns `undefined` before the layer is initialized. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const sourceLayer = t.layers.add(); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +function drawCenteredText(text, y, rgb = [255, 255, 255]) { + drawText(text, -Math.floor(text.length / 2), y, rgb); +} + +sourceLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.03; + + t.push(); + t.rotateZ((time * 180) / Math.PI); + t.charColor(255, 180, 100); + t.char('#'); + t.rect(14, 1); + t.rect(1, 14); + t.pop(); +}); + +t.draw(() => { + t.background(6, 10, 22); + + const fb = sourceLayer.drawFramebuffer; + + if (fb) { + t.push(); + t.translate(0, 0); + t.image(fb, 24, 14); + t.pop(); + + drawCenteredText('INTERNAL DATA BUFFER', 10, [140, 220, 255]); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const fb = sourceLayer.drawFramebuffer; + + drawText('TEXTMODELAYER.DRAWFRAMEBUFFER', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: RAW DRAW BUFFER', x, y++, [100, 220, 255]); + drawText('Captures pre-ASCII drawing.', x, y++, [140, 160, 190]); + drawText('Image preview reads the buffer.', x, y++, [140, 160, 190]); + if (!fb) return; + + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`SIZE: ${fb.width} x ${fb.height}`, x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md index a99430b2..dfe6b212 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md @@ -32,5 +32,79 @@ Font or tileset used by this layer. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const bigFontLayer = t.layers.add({ fontSize: 32, blendMode: 'additive' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); + t.pop(); +}); + +bigFontLayer.draw(() => { + t.clear(); + const font = bigFontLayer.font; + const chars = font.characters; + const time = t.frameCount * 0.02; + + const cols = 8; + const rows = 3; + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + const idx = (r * cols + c + Math.floor(time * 10)) % chars.length; + const glyph = chars[idx]; + + t.push(); + t.translate(c - Math.floor(cols / 2), r - Math.floor(rows / 2)); + t.char(glyph.character); + t.charColor(120, 180, 255); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const baseSize = t.layers.base.font.fontSize; + const layerSize = bigFontLayer.font.fontSize; + + drawText('TEXTMODELAYER.FONT', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER FONT STATE', x, y++, [100, 220, 255]); + drawText('Base and overlay keep fonts apart.', x, y++, [140, 160, 190]); + drawText('Large font layer uses additive.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`BASE FONT: ${baseSize} PX`, x, y++, [140, 180, 255]); + drawText(`LAYER FONT: ${layerSize} PX`, x, y++, [255, 225, 140]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md index bca4e205..10295fd1 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md @@ -29,5 +29,66 @@ Grid associated with this layer. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const densityLayer = t.layers.add({ fontSize: 8, blendMode: 'screen' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.translate(-10, 0); + t.charColor(100, 150, 255, 100); + t.char('+'); + t.rect(14, 10); + t.pop(); +}); + +densityLayer.draw(() => { + t.clear(); + + t.push(); + t.translate(20, 0); + t.charColor(255, 225, 140, 150); + t.char('+'); + t.rect(28, 20); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const g = densityLayer.grid; + + drawText('TEXTMODELAYER.GRID', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: INDEPENDENT GRID', x, y++, [100, 220, 255]); + drawText('Each layer gets its own grid.', x, y++, [140, 160, 190]); + drawText('Font size changes cell count.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`BASE: ${t.grid.cols} x ${t.grid.rows}`, x, y++, [140, 180, 255]); + drawText(`LAYER: ${g.cols} x ${g.rows}`, x, y++, [255, 225, 140]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md index 93e750ab..7e5cf6c6 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md @@ -31,5 +31,59 @@ Returns `0` before the layer is initialized. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const detailLayer = t.layers.add({ fontSize: 8 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.translate(0, 0); + t.char('|'); + t.charColor(120, 180, 255, 100); + t.rect(1, t.grid.rows); + t.pop(); +}); + +detailLayer.draw(() => { + t.clear(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const g = detailLayer.grid; + + drawText('TEXTMODELAYER.HEIGHT', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER PIXEL HEIGHT', x, y++, [100, 220, 255]); + drawText('Reports ASCII framebuffer height.', x, y++, [140, 160, 190]); + drawText('Finer font size gives more rows.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`${detailLayer.height} PIXELS`, x, y++, [140, 255, 180]); + drawText(`${g.rows} ROWS x ${g.cellHeight}PX`, x, y++, [120, 200, 255]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md index 0a7d8af2..3816790a 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md @@ -31,5 +31,62 @@ Returns `undefined` before the layer is initialized. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const layer = t.layers.add({ fontSize: 16, blendMode: 'screen' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [220, 230, 255]) { + t.push(); + t.translate(x, y); + t.charColor(rgb[0], rgb[1], rgb[2]); + + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + + t.pop(); +} + +t.draw(() => { + t.background(5, 7, 18); +}); + +layer.draw(() => { + t.clear(); + t.push(); + t.rotateZ(t.frameCount * 1.5); + t.charColor(120, 205, 255); + t.rect(18, 8); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const ready = layer.texture === layer.asciiFramebuffer.textures[0]; + + drawText('TEXTMODELAYER.TEXTURE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: ASCII TEXTURE HANDLE', x, y++, [100, 220, 255]); + drawText('Exposes the composited texture.', x, y++, [140, 160, 190]); + drawText('Matches asciiFramebuffer tex 0.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(ready ? 'TEXTURE: READY' : 'TEXTURE: PENDING', x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md index 37529e78..32c72095 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md @@ -31,5 +31,59 @@ Returns `0` before the layer is initialized. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const detailLayer = t.layers.add({ fontSize: 8 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.translate(0, 0); + t.char('='); + t.charColor(120, 180, 255, 100); + t.rect(t.grid.cols, 1); + t.pop(); +}); + +detailLayer.draw(() => { + t.clear(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const g = detailLayer.grid; + + drawText('TEXTMODELAYER.WIDTH', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER PIXEL WIDTH', x, y++, [100, 220, 255]); + drawText('Reports ASCII framebuffer width.', x, y++, [140, 160, 190]); + drawText('A finer layer has more cells.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`${detailLayer.width} PIXELS`, x, y++, [140, 255, 180]); + drawText(`${g.cols} CELLS x ${g.cellWidth}PX`, x, y++, [120, 200, 255]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md index 0e0bae7c..a534aa41 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md @@ -38,5 +38,91 @@ Current blend mode as a numeric [LayerBlendMode](../../../enumerations/LayerBlen ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const blendModes = [t.BLEND_ADDITIVE, t.BLEND_SCREEN, t.BLEND_OVERLAY, t.BLEND_DIFFERENCE, t.BLEND_MULTIPLY]; +const colors = [ + [255, 80, 150], + [80, 180, 255], + [255, 200, 80], + [150, 255, 120], + [200, 120, 255], +]; + +const layers = blendModes.map((mode) => t.layers.add({ blendMode: mode, opacity: 0.9 })); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.translate(x, y); + t.charColor(rgb[0], rgb[1], rgb[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +function drawCenteredText(text, y, rgb = [255, 255, 255]) { + drawText(text, -Math.floor(text.length / 2), y, rgb); +} + +t.draw(() => { + const time = t.frameCount * 0.02; + t.background(10, 15, 25); + + const { cols, rows } = t.grid; + + t.char('+'); + t.charColor(40, 50, 80); + t.rect(cols, rows); + + layers.forEach((layer, i) => { + layer.draw(() => { + t.clear(); + t.push(); + + const angle = (i / layers.length) * Math.PI * 2 + time; + const radius = 8 + Math.sin(time * 2) * 2; + t.translate(Math.cos(angle) * radius, Math.sin(angle) * radius); + + t.charColor(...colors[i]); + t.char('@'); + t.rect(14, 8); + + drawCenteredText(blendModes[i], 0, [255, 255, 255]); + + t.pop(); + }); + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const active = blendModes[Math.floor(t.frameCount / 80) % blendModes.length]; + + drawText('TEXTMODELAYER.BLENDMODE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: PER-LAYER BLENDING', x, y++, [100, 220, 255]); + drawText('Each layer composites differently.', x, y++, [140, 160, 190]); + drawText('Opacity is set per layer too.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`MODES: ${blendModes.length}`, x, y++, [140, 255, 180]); + drawText(`WATCH: ${active}`, x, y++, [120, 200, 255]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md index 88007f9b..7ad744cf 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md @@ -50,5 +50,96 @@ Set explicit camera parameters for this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let camX = 0; +const camY = 10; +const camZ = 42; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 18); + + const time = t.frameCount * 0.03; + camX = Math.sin(time) * 22; + + // Update layer camera + scene.camera(camX, camY, camZ, 0, 0, 0); +}); + +scene.draw(() => { + t.clear(); + t.pointLight([255, 200, 120], { x: 20, y: -15, z: 30 }); + + // Rotate center shape group + t.push(); + t.rotateY(t.frameCount * 1.5); + + // Center cube + t.push(); + t.char('#'); + t.charColor(120, 220, 255); + t.box(8, 8, 8); + t.pop(); + + // Left pillar + t.push(); + t.translate(-12, 0, 0); + t.char('H'); + t.charColor(255, 120, 120); + t.box(4, 12, 4); + t.pop(); + + // Right pillar + t.push(); + t.translate(12, 0, 0); + t.char('O'); + t.charColor(120, 255, 120); + t.box(4, 12, 4); + t.pop(); + + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const eyeStr = `Cam Eye : [${camX.toFixed(1)}, ${camY.toFixed(1)}, ${camZ.toFixed(1)}]`; + drawText('TEXTMODELAYER.CAMERA', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER CAMERA', x, y++, [100, 220, 255]); + drawText('Sets a 3D camera on one layer.', x, y++, [140, 160, 190]); + drawText('Base background stays flat.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(eyeStr, x, y++, [120, 255, 180]); + drawText('Target: [0.0, 0.0, 0.0]', x, y++, [200, 200, 200]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md index 1de172b9..217fa825 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md @@ -29,5 +29,100 @@ The created camera. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let camera; +let camX = 0; +const camY = 8; +const camZ = 46; + +t.setup(() => { + camera = scene.createCamera(); + scene.setCamera(camera); +}); + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 18); + + camX = Math.sin(t.frameCount * 0.03) * 22; + + // Move and aim the layer camera each frame + camera.setPosition(camX, camY, camZ); + camera.lookAt(0, 0, 0); +}); + +scene.draw(() => { + t.clear(); + t.pointLight([255, 200, 120], { x: 20, y: -15, z: 30 }); + + // Rotate center shape group + t.push(); + t.rotateY(t.frameCount * 1.5); + + // Center cube + t.push(); + t.char('#'); + t.charColor(120, 220, 255); + t.box(8, 8, 8); + t.pop(); + + // Left pillar + t.push(); + t.translate(-12, 0, 0); + t.char('H'); + t.charColor(255, 120, 120); + t.box(4, 12, 4); + t.pop(); + + // Right pillar + t.push(); + t.translate(12, 0, 0); + t.char('O'); + t.charColor(120, 255, 120); + t.box(4, 12, 4); + t.pop(); + + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + let y = -Math.floor(t.grid.rows / 2) + 3; + const x = -Math.floor(t.grid.cols / 2) + 3; + + const eyeStr = `Cam Eye : [${camX.toFixed(1)}, ${camY.toFixed(1)}, ${camZ.toFixed(1)}]`; + drawText('TEXTMODELAYER.CREATECAMERA', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: OWNED CAMERA', x, y++, [100, 220, 255]); + drawText('Creates a camera for this layer.', x, y++, [140, 160, 190]); + drawText('Then setCamera activates it.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(eyeStr, x, y++, [120, 255, 180]); + drawText('Target: [0.0, 0.0, 0.0]', x, y++, [200, 200, 200]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md index e3af5c3c..e907ce07 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md @@ -33,5 +33,79 @@ Delete plugin-specific state from this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const layer = t.layers.add(); +const labelLayer = t.layers.add(); +const PLUGIN_NAME = 'monitor'; +let stateDeleted = false; +let latestAngle = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.mousePressed(() => { + if (layer.hasPluginState(PLUGIN_NAME)) { + layer.deletePluginState(PLUGIN_NAME); + stateDeleted = true; + } +}); + +layer.draw(() => { + t.clear(); + + if (!layer.hasPluginState(PLUGIN_NAME)) { + layer.setPluginState(PLUGIN_NAME, { angle: 0, resets: 0 }); + } + + const state = layer.getPluginState(PLUGIN_NAME); + + state.angle += 0.05; + latestAngle = state.angle; + + t.push(); + t.rotateZ((state.angle * 180) / Math.PI); + t.charColor(120, 180, 255); + t.char('#'); + t.rect(8, 4); + t.pop(); +}); + +t.draw(() => { + t.background(6, 10, 22); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const statusColor = stateDeleted ? [255, 180, 100] : [120, 255, 150]; + + drawText('TEXTMODELAYER.DELETEPLUGINSTATE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: DELETE PLUGIN STATE', x, y++, [100, 220, 255]); + drawText('Click clears the monitor state.', x, y++, [140, 160, 190]); + drawText('Draw recreates it next frame.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(stateDeleted ? 'STATE: RECREATED' : 'STATE: ACTIVE', x, y++, statusColor); + drawText(`ANGLE: ${latestAngle.toFixed(2)}`, x, y++, [180, 200, 220]); + stateDeleted = false; +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md index a17f0efe..2014db33 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md @@ -35,5 +35,88 @@ The callback runs each frame and should contain this layer's drawing commands. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const backLayer = t.layers.add({ opacity: 0.6 }); +const effectLayer = t.layers.add({ blendMode: 'additive' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + for (let y = -4; y <= 4; y += 2) { + t.push(); + t.translate(0, y); + t.rect(t.grid.cols, 1); + t.pop(); + } + t.pop(); +}); + +backLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.03; + + // Floating data nodes circling the center + for (let i = 0; i < 6; i++) { + const angle = time + (i / 6) * Math.PI * 2; + const r = 10; + t.push(); + t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); + t.charColor(100, 150, 255); + t.char('o'); + t.point(); + t.pop(); + } +}); + +effectLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.05; + const pulse = 0.5 + 0.5 * Math.sin(time); + + // Central core pulsing shape + t.push(); + t.charColor(255, 100 + pulse * 155, 100); + t.char('#'); + t.rect(8, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.DRAW', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER DRAW CALLBACK', x, y++, [100, 220, 255]); + drawText('Base, back, and effect draw apart.', x, y++, [140, 160, 190]); + drawText('Each callback owns its buffer.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('LAYERS: BASE + 2', x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md index b32d5be9..1aaaf068 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md @@ -51,7 +51,87 @@ Call this method within your layer's draw callback to apply effects. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const effectLayer = t.layers.add(); +const labelLayer = t.layers.add(); + +const filters = [ + { name: 'invert', params: undefined, label: 'INVERT' }, + { name: 'grayscale', params: 1.0, label: 'GRAYSCALE (1.0)' }, + { name: 'sepia', params: 0.8, label: 'SEPIA (0.8)' }, + { name: 'threshold', params: 0.5, label: 'THRESHOLD (0.5)' }, +]; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); + t.pop(); +}); + +effectLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.02; + + for (let i = 0; i < 8; i++) { + const angle = time + (i / 8) * Math.PI * 2; + const r = 8 + Math.sin(time * 2) * 2; + t.push(); + t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); + t.charColor(100 + i * 20, 255 - i * 10, 150 + i * 10); + t.char('#'); + t.point(); + t.pop(); + } + + const filterIdx = Math.floor(t.frameCount / 120) % (filters.length + 1); + + if (filterIdx < filters.length) { + const active = filters[filterIdx]; + effectLayer.filter(active.name, active.params); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const filterIdx = Math.floor(t.frameCount / 120) % (filters.length + 1); + const active = filterIdx < filters.length ? filters[filterIdx].label : 'NORMAL'; + + drawText('TEXTMODELAYER.FILTER', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER POST FILTERS', x, y++, [100, 220, 255]); + drawText('Only the effect layer changes.', x, y++, [140, 160, 190]); + drawText('Base grid remains unfiltered.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`ACTIVE: ${active}`, x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Call Signature diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md index 7923c951..f257c237 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md @@ -37,5 +37,74 @@ Current font size when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const detailLayer = t.layers.add({ fontSize: 8, blendMode: 'screen' }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.translate(0, 0); + t.charColor(40, 50, 80); + t.char('#'); + t.rect(20, 10); + t.pop(); +}); + +detailLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.03; + + t.push(); + t.translate(0, -2); + t.charColor(255, 225, 140, 150); + t.char('.'); + + for (let i = 0; i < 40; i++) { + const angle = time + i * 0.2; + const r = 12 + Math.sin(time + i * 0.5) * 4; + t.push(); + t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); + t.point(); + t.pop(); + } + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.FONTSIZE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: PER-LAYER RESOLUTION', x, y++, [100, 220, 255]); + drawText('Smaller font gives denser cells.', x, y++, [140, 160, 190]); + drawText('Layer grids update independently.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`BASE: ${t.layers.base.fontSize()} PX`, x, y++, [140, 180, 255]); + drawText(`DETAIL: ${detailLayer.fontSize()} PX`, x, y++, [255, 225, 140]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md index 5668b0ee..c4c89764 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md @@ -41,5 +41,89 @@ Stored state, or `undefined` when not set. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const trackerLayer = t.layers.add(); +const labelLayer = t.layers.add(); +const PLUGIN_NAME = 'tracker'; +let latestX = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +trackerLayer.setPluginState(PLUGIN_NAME, { + x: 0, + speed: 0.1, + amplitude: 15, +}); + +trackerLayer.draw(() => { + t.clear(); + + const state = trackerLayer.getPluginState(PLUGIN_NAME); + + if (state) { + state.x += state.speed; + const xPos = Math.round(Math.cos(state.x) * state.amplitude); + latestX = xPos; + + t.push(); + t.translate(xPos, 0); + t.charColor(120, 200, 255); + t.char('#'); + t.point(); + + t.push(); + t.translate(0, 3); + t.char('^'); + t.charColor(60, 70, 100); + t.point(); + t.pop(); + t.pop(); + } +}); + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, 1); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const state = trackerLayer.getPluginState(PLUGIN_NAME); + const xText = latestX.toString().padStart(3, ' '); + + drawText('TEXTMODELAYER.GETPLUGINSTATE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: READ PLUGIN STATE', x, y++, [100, 220, 255]); + drawText('Persistent data drives motion.', x, y++, [140, 160, 190]); + drawText('The layer owns the stored object.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`X: ${xText}`, x, y++, [180, 200, 220]); + drawText(`SPEED: ${state.speed.toFixed(2)}`, x, y++, [180, 200, 220]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md index 68811606..bd1e8bda 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md @@ -35,5 +35,75 @@ Check whether plugin-specific state exists on this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const layer = t.layers.add(); +const labelLayer = t.layers.add(); +const PLUGIN_NAME = 'module'; +let exists = false; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + if (t.frameCount % 120 === 0) { + if (layer.hasPluginState(PLUGIN_NAME)) { + layer.deletePluginState(PLUGIN_NAME); + } else { + layer.setPluginState(PLUGIN_NAME, { active: true }); + } + } + + exists = layer.hasPluginState(PLUGIN_NAME); + const statusColor = exists ? [120, 255, 150] : [255, 100, 100]; + + t.push(); + t.translate(0, 0); + t.char(exists ? '#' : '.'); + t.charColor(exists ? statusColor : [60, 70, 100]); + t.rect(10, 5); + + t.push(); + t.translate(0, 0); + t.charColor(statusColor); + t.char('o'); + t.point(); + t.pop(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const statusColor = exists ? [120, 255, 150] : [255, 100, 100]; + + drawText('TEXTMODELAYER.HASPLUGINSTATE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: CHECK PLUGIN STATE', x, y++, [100, 220, 255]); + drawText('The module state toggles on/off.', x, y++, [140, 160, 190]); + drawText('hasPluginState returns a boolean.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(exists ? 'STATUS: CONNECTED' : 'STATUS: DISCONNECTED', x, y++, statusColor); + drawText(`HAS '${PLUGIN_NAME}': ${exists}`, x, y++, [140, 180, 255]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md index ad9e5431..cfe9a5ee 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md @@ -27,5 +27,102 @@ Hide this layer from rendering. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const signalLayer = t.layers.add({ blendMode: 'additive' }); +const labelLayer = t.layers.add(); +let isVisible = true; + +t.draw(() => { + t.background(6, 10, 22); + + if (t.frameCount % 120 === 0) { + if (isVisible) { + signalLayer.hide(); + } else { + signalLayer.show(); + } + isVisible = !isVisible; + } + + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + + t.push(); + t.charColor(30, 45, 75); + t.char('+'); + for (let y = -hh; y <= hh; y += 6) { + for (let x = -hw; x <= hw; x += 10) { + t.push(); + t.translate(x, y); + t.point(); + t.pop(); + } + } + t.pop(); +}); + +signalLayer.draw(() => { + t.clear(); + const tm = t.frameCount * 0.04; + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + + const trail = ['*', 'o', '.', ':']; + for (let i = 0; i < 16; i++) { + const angle = tm - i * 0.08; + const r = Math.min(hw, hh) * 0.5; + const px = Math.floor(Math.cos(angle) * r); + const py = Math.floor(Math.sin(angle) * (r * 0.6)); + const idx = Math.min(trail.length - 1, Math.floor((i / 16) * trail.length)); + + t.push(); + t.translate(px, py); + t.charColor(Math.floor(255 - i * 12), Math.floor(200 - i * 10), Math.floor(60 + i * 10)); + t.cellColor(30, 20, 5); + t.char(trail[idx]); + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODELAYER.HIDE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: CONTINUOUS RADAR STATE MASKING', x, y++); + t.charColor(140, 160, 190); + t.print('hide() pauses layer composition.', x, y++); + t.print('Background particle state advances.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + if (isVisible) { + t.charColor(140, 255, 180); + t.print('STATUS: VISIBLE (SIGNAL ON)', x, y++); + } else { + t.charColor(255, 120, 120); + t.print('STATUS: HIDDEN (STATE CONTINUES)', x, y++); + } + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md index df1206d7..0c2bfe0c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md @@ -35,5 +35,96 @@ The loaded TextmodeTileset. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const tilesLayer = t.layers.add(); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(async () => { + await tilesLayer.loadTileset({ + source: 'https://littlebitspace.com/resources/fonts/T64.png', + columns: 16, + rows: 16, + count: 256, + }); + + // Use authored colors from the tileset PNG + tilesLayer.useTileColors(true); +}); + +t.draw(() => { + t.background(6, 10, 22); +}); + +tilesLayer.draw(() => { + t.clear(); + + const font = tilesLayer.font; + if (!font || font.characters.length === 0) return; + + const time = t.frameCount * 0.04; + const activeTile = Math.floor(time) % font.characters.length; + + const cols = 16; + const startX = -Math.floor(cols / 2); + const startY = -4; + + // Draw all tiles in a grid + for (let i = 0; i < font.characters.length; i++) { + const col = i % cols; + const row = Math.floor(i / cols); + t.push(); + t.translate(startX + col, startY + row); + t.char(i); + + // Highlight the currently cycled tile + if (i === activeTile) { + t.charColor(255, 255, 100); + } + + t.point(); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const font = tilesLayer.font; + const count = font ? font.characters.length : 0; + + drawText('TEXTMODELAYER.LOADTILESET', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LOAD TILESET', x, y++, [100, 220, 255]); + drawText('Loads bitmap glyphs into a layer.', x, y++, [140, 160, 190]); + drawText('Tile colors are authored in PNG.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`TILES LOADED: ${count}`, x, y++, [120, 255, 180]); + drawText('SOURCE: T64 PNG, 16 x 16', x, y++, [160, 160, 160]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md index a4a339f5..40a5fdfe 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md @@ -44,5 +44,96 @@ Update this layer camera's target and optional up vector. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let targetX = 0; +let targetY = 0; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 18); + + targetX = Math.sin(t.frameCount * 0.04) * 12; + targetY = Math.cos(t.frameCount * 0.03) * 7; + + // Camera stays fixed — only the look target moves + scene.camera(0, 0, 46); + scene.lookAt(targetX, targetY, 0); +}); + +scene.draw(() => { + t.clear(); + + // Static reference pillars spread around the scene + t.push(); + t.translate(-16, 4, -10); + t.char('H'); + t.charColor(100, 130, 200); + t.box(5, 14, 5); + t.pop(); + + t.push(); + t.translate(16, 4, -10); + t.char('H'); + t.charColor(100, 130, 200); + t.box(5, 14, 5); + t.pop(); + + t.push(); + t.translate(0, 8, -18); + t.char('+'); + t.charColor(80, 100, 160); + t.box(30, 2, 2); + t.pop(); + + // Moving glowing target — the camera tracks this + t.push(); + t.translate(targetX, targetY, 0); + t.char('*'); + t.charColor(255, 230, 80); + t.box(4, 4, 4); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const tgtStr = `Cam Target: [${targetX.toFixed(1)}, ${targetY.toFixed(1)}, 0.0]`; + + drawText('TEXTMODELAYER.LOOKAT', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: CAMERA TARGET', x, y++, [100, 220, 255]); + drawText('Camera eye stays fixed.', x, y++, [140, 160, 190]); + drawText('lookAt follows a moving target.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('Eye: [0.0, 0.0, 46.0]', x, y++, [200, 200, 200]); + drawText(tgtStr, x, y++, [120, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md index 138148b6..c4e589c7 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md @@ -45,5 +45,82 @@ Current offset when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const offsetLayer = t.layers.add({ blendMode: 'additive' }); +const labelLayer = t.layers.add(); +let currentOffset = { x: 0, y: 0 }; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + const time = t.frameCount * 0.03; + const g = t.grid; + + const offX = Math.round(Math.cos(time) * (g.width * 0.25)); + const offY = Math.round(Math.sin(time * 0.7) * (g.height * 0.25)); + + currentOffset = { x: offX, y: offY }; + offsetLayer.offset(offX, offY); + + const targetGridX = Math.round(offX / g.cellWidth); + const targetGridY = Math.round(offY / g.cellHeight); + + t.push(); + t.charColor(60, 70, 100, 150); + t.char('.'); + t.line(0, 0, targetGridX, targetGridY); + t.pop(); + + t.push(); + t.charColor(100, 120, 150); + t.char('+'); + t.point(); + t.pop(); +}); + +offsetLayer.draw(() => { + t.clear(); + + t.push(); + t.charColor(255, 180, 100); + t.char('#'); + t.rect(7, 3); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.OFFSET', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: PIXEL OFFSET', x, y++, [100, 220, 255]); + drawText('Moves the layer during composite.', x, y++, [140, 160, 190]); + drawText('Drawing coordinates stay local.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`OFFSET X: ${currentOffset.x} PX`, x, y++, [255, 180, 100]); + drawText(`OFFSET Y: ${currentOffset.y} PX`, x, y++, [255, 180, 100]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md index ef8251a3..ddd758e8 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md @@ -35,5 +35,89 @@ Current opacity when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const pulseLayer = t.layers.add({ blendMode: 'additive' }); +const labelLayer = t.layers.add(); +let currentOpacity = 1; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +function drawMeter(value, x, y, rgb) { + const width = 20; + const activeBlocks = Math.round(value * width); + + t.push(); + t.translate(x, y); + for (let i = 0; i < width; i++) { + const active = i < activeBlocks; + const color = active ? rgb : [60, 70, 100]; + t.push(); + t.translate(i, 0); + t.char(active ? '|' : '.'); + t.charColor(color[0], color[1], color[2]); + t.point(); + t.pop(); + } + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + const time = t.frameCount * 0.04; + const opacity = 0.5 + 0.5 * Math.sin(time); + + currentOpacity = opacity; + pulseLayer.opacity(opacity); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); + t.pop(); +}); + +pulseLayer.draw(() => { + t.clear(); + + t.push(); + t.charColor(255, 140, 180); + t.char('#'); + t.rect(12, 6); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.OPACITY', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: LAYER ALPHA', x, y++, [100, 220, 255]); + drawText('Pulse layer fades in and out.', x, y++, [140, 160, 190]); + drawText('Opacity is clamped from 0 to 1.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawMeter(currentOpacity, x, y++, [255, 225, 140]); + drawText(`OPACITY: ${currentOpacity.toFixed(2)}`, x, y++, [255, 225, 140]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md index 6664d401..d8c6ec55 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md @@ -34,5 +34,88 @@ Enable orthographic projection for this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ['.', ':', '=', '#', '%']; +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 22); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + t.push(); + t.translate(x, y); + t.charColor(20, 30, 55); + t.cellColor(6, 10, 22); + t.char('.'); + t.point(); + t.pop(); + } + } + scene.ortho(); + scene.camera(30, 24, 30); +}); + +scene.draw(() => { + t.clear(); + const tm = t.frameCount * 0.03; + t.push(); + t.ambientLight(25, 35, 60); + t.pointLight(255, 200, 140, Math.sin(tm) * 15, 20, 20); + + for (let x = -16; x <= 16; x += 8) { + for (let z = -16; z <= 16; z += 8) { + const norm = Math.sin(x * 0.2 + z * 0.2 + tm) * 0.5 + 0.5; + const h = Math.floor(norm * 10 + 4); + const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); + + t.push(); + t.translate(x, h * 0.5, z); + t.charColor(Math.floor(40 + norm * 140), Math.floor(180 + norm * 60), Math.floor(220 - norm * 80)); + t.cellColor(10, 20, 38); + t.char(RAMP[idx]); + t.box(4, h, 4); + t.pop(); + } + } + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODELAYER.ORTHO', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ISOMETRIC ARCHITECTURAL MATRIX', x, y++); + t.charColor(140, 160, 190); + t.print('Enables orthographic layer projection.', x, y++); + t.print('Objects retain scale regardless of depth.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('PROJECTION: PARALLEL ORTHOGRAPHIC', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md index 9ffab38d..0ccade4b 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md @@ -38,5 +38,95 @@ Enable perspective projection for this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let fov = 60; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 18); + + // FOV oscillates between 20° (telephoto) and 100° (wide) + fov = 60 + Math.sin(t.frameCount * 0.025) * 40; + + scene.perspective(fov, 0.1, 256); + scene.camera(0, 0, 44); + scene.lookAt(0, 0, 0); +}); + +scene.draw(() => { + t.clear(); + t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); + + // Three columns at increasing depth to show perspective compression + const depths = [0, -12, -24]; + const colors = [ + [120, 200, 255], + [160, 220, 180], + [255, 180, 120], + ]; + + for (let i = 0; i < 3; i++) { + t.push(); + t.translate(0, 0, depths[i]); + t.char('#'); + t.charColor(colors[i][0], colors[i][1], colors[i][2]); + t.box(8, 8, 8); + t.pop(); + } + + // Floor grid for depth reference + t.push(); + t.char('.'); + t.charColor(40, 55, 80); + for (let x = -24; x <= 24; x += 8) { + t.line(x, 6, 4, x, 6, -32); + } + for (let z = 4; z >= -32; z -= 8) { + t.line(-24, 6, z, 24, 6, z); + } + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const fovStr = `FOV: ${fov.toFixed(1)} deg`; + drawText('TEXTMODELAYER.PERSPECTIVE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: PERSPECTIVE FOV', x, y++, [100, 220, 255]); + drawText('FOV changes depth compression.', x, y++, [140, 160, 190]); + drawText('Near/far clip the layer camera.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(fovStr, x, y++, [120, 255, 180]); + drawText('NEAR: 0.1 FAR: 256.0', x, y++, [200, 200, 200]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md index 3ab9585b..22a7cecb 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md @@ -27,5 +27,97 @@ Reset this layer to default auto camera behavior. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let useCustomCamera = true; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.draw(() => { + t.background(8, 10, 18); + + // Alternate every 150 frames so the contrast is clear + useCustomCamera = Math.floor(t.frameCount / 150) % 2 === 0; + + if (useCustomCamera) { + // Dramatic off-axis perspective with moving eye + const camX = Math.sin(t.frameCount * 0.02) * 18; + scene.camera(camX, -14, 42, 0, 0, 0); + } else { + // Discard custom camera — auto view is restored + scene.resetCamera(); + } +}); + +scene.draw(() => { + t.clear(); + t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); + + const positions = [ + [-12, 0, 0], + [0, 0, -12], + [12, 0, 0], + ]; + const colors = [ + [120, 200, 255], + [200, 160, 255], + [255, 180, 120], + ]; + + for (let i = 0; i < 3; i++) { + t.push(); + t.translate(positions[i][0], positions[i][1], positions[i][2]); + t.char('#'); + t.charColor(colors[i][0], colors[i][1], colors[i][2]); + t.box(7, 7, 7); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.RESETCAMERA', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: RESET LAYER CAMERA', x, y++, [100, 220, 255]); + + if (useCustomCamera) { + drawText('MODE: CUSTOM CAMERA', x, y++, [255, 200, 100]); + drawText('camera() override is active.', x, y++, [140, 160, 190]); + } else { + drawText('MODE: AUTO CAMERA', x, y++, [120, 255, 180]); + drawText('resetCamera restored default.', x, y++, [140, 160, 190]); + } + + drawText('------------------------------------', x, y++, [80, 100, 150]); + const remaining = 150 - (t.frameCount % 150); + drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [200, 200, 200]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md index aee62475..545af200 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md @@ -39,5 +39,77 @@ Current rotation in degrees when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scannerLayer = t.layers.add({ blendMode: 'additive' }); +const labelLayer = t.layers.add(); +let currentAngle = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + const time = t.frameCount * 1.5; + const angle = time % 360; + + currentAngle = angle; + scannerLayer.rotateZ(angle); + + t.push(); + t.charColor(60, 70, 100); + t.char('.'); + t.line(-15, 0, 15, 0); + t.line(0, -8, 0, 8); + t.pop(); +}); + +scannerLayer.draw(() => { + t.clear(); + + t.push(); + t.charColor(140, 180, 255, 200); + t.char('#'); + t.rect(20, 1); + t.pop(); + + t.push(); + t.translate(10, 0); + t.char('>'); + t.charColor(255, 225, 140); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODELAYER.ROTATEZ', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: COMPOSITE ROTATION', x, y++, [100, 220, 255]); + drawText('Layer output rotates around center.', x, y++, [140, 160, 190]); + drawText('Draw callback remains unrotated.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`ANGLE: ${currentAngle.toFixed(1)} DEG`, x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md index 04f9b9c7..281fbc05 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md @@ -33,5 +33,100 @@ Activate a camera for this layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const scene = t.layers.add(); +const labelLayer = t.layers.add(); + +let camA; +let camB; +let activeCam = 'A'; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(() => { + camA = scene.createCamera(); + camA.setPosition(-22, -8, 40).lookAt(0, 0, 0); + camB = scene.createCamera(); + camB.setPosition(22, 12, 36).lookAt(0, 0, 0); + scene.setCamera(camA); +}); + +t.draw(() => { + t.background(8, 10, 18); + const slot = Math.floor(t.frameCount / 150) % 2; + if (slot === 0 && activeCam !== 'A') { + scene.setCamera(camA); + activeCam = 'A'; + } else if (slot === 1 && activeCam !== 'B') { + scene.setCamera(camB); + activeCam = 'B'; + } +}); + +scene.draw(() => { + t.clear(); + t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); + const positions = [ + [-12, 0, 0], + [0, 0, -12], + [12, 0, 0], + ]; + const colors = [ + [120, 200, 255], + [200, 160, 255], + [255, 180, 120], + ]; + for (let i = 0; i < 3; i++) { + t.push(); + t.translate(positions[i][0], positions[i][1], positions[i][2]); + t.char('#'); + t.charColor(colors[i][0], colors[i][1], colors[i][2]); + t.box(7, 7, 7); + t.pop(); + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const isA = activeCam === 'A'; + drawText('TEXTMODELAYER.SETCAMERA', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: SWAP ACTIVE CAMERA', x, y++, [100, 220, 255]); + drawText('Two owned cameras alternate.', x, y++, [140, 160, 190]); + drawText('setCamera selects the view.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`ACTIVE: CAMERA ${activeCam}`, x, y++, isA ? [120, 200, 255] : [255, 180, 120]); + if (isA) { + drawText('EYE: [-22, -8, 40]', x, y++, [200, 200, 200]); + } else { + drawText('EYE: [22, 12, 36]', x, y++, [200, 200, 200]); + } + const remaining = 150 - (t.frameCount % 150); + drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [160, 160, 160]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md index 04519f02..e89c195d 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md @@ -41,5 +41,84 @@ Plugins can use this to attach their own data to layer instances. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const moduleLayer = t.layers.add(); +const labelLayer = t.layers.add(); +const PLUGIN_NAME = 'core-data'; +let currentPower = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + moduleLayer.setPluginState(PLUGIN_NAME, { + power: 0, + sync: true, + id: 'CORE-A1', + }); +}); + +moduleLayer.draw(() => { + t.clear(); + const state = moduleLayer.getPluginState(PLUGIN_NAME); + + if (state) { + state.power = 0.5 + 0.5 * Math.sin(t.frameCount * 0.05); + currentPower = state.power; + + t.push(); + t.charColor(140, 220, 255); + t.char('#'); + const size = 4 + Math.round(state.power * 4); + t.rect(size * 2, size); + t.pop(); + } +}); + +t.draw(() => { + t.background(6, 10, 22); + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const state = moduleLayer.getPluginState(PLUGIN_NAME); + const load = Math.round(currentPower * 100); + + drawText('TEXTMODELAYER.SETPLUGINSTATE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: STORE PLUGIN STATE', x, y++, [100, 220, 255]); + drawText('Attaches data to a layer.', x, y++, [140, 160, 190]); + drawText('The object persists each frame.', x, y++, [140, 160, 190]); + if (!state) return; + + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`ID: ${state.id}`, x, y++, [180, 200, 220]); + drawText(`PWR LOAD: ${load}%`, x, y++, [140, 220, 255]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md index 93722b3d..c80ea166 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md @@ -27,5 +27,81 @@ Show this layer for rendering. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const displayLayer = t.layers.add({ visible: false, blendMode: 'additive' }); +const labelLayer = t.layers.add(); +let isVisible = false; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 10, 22); + + if (t.frameCount % 120 === 0) { + if (isVisible) { + displayLayer.hide(); + } else { + displayLayer.show(); + } + isVisible = !isVisible; + } + + t.push(); + t.charColor(40, 50, 80); + t.char('.'); + t.rect(t.grid.cols, t.grid.rows); + t.pop(); +}); + +displayLayer.draw(() => { + t.clear(); + const time = t.frameCount * 0.03; + + t.push(); + t.charColor(255, 180, 100); + t.char('#'); + t.rotateZ((time * 180) / Math.PI); + t.rect(12, 12); + t.pop(); + + t.push(); + t.charColor(255, 225, 140); + t.char('+'); + t.point(); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + const statusColor = isVisible ? [140, 255, 180] : [255, 100, 100]; + + drawText('TEXTMODELAYER.SHOW', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: SHOW HIDDEN LAYER', x, y++, [100, 220, 255]); + drawText('show() restores compositing.', x, y++, [140, 160, 190]); + drawText('hide() pauses visible output.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(isVisible ? 'LAYER: VISIBLE' : 'LAYER: HIDDEN', x, y++, statusColor); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md index 9f6a4896..11ddab97 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md @@ -39,5 +39,100 @@ Current tileset-color mode when called without arguments. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const tilesLayer = t.layers.add(); +const labelLayer = t.layers.add(); + +let useAuthored = false; + +function drawText(text, x, y, color = [200, 220, 255]) { + t.push(); + t.translate(x, y); + t.charColor(color[0], color[1], color[2]); + for (let i = 0; i < text.length; i++) { + t.char(text[i]); + t.point(); + t.translate(1, 0); + } + t.pop(); +} + +t.setup(async () => { + await tilesLayer.loadTileset({ + source: 'https://littlebitspace.com/resources/fonts/T64.png', + columns: 16, + rows: 16, + count: 256, + }); +}); + +t.draw(() => { + t.background(6, 10, 22); + useAuthored = Math.floor(t.frameCount / 150) % 2 === 0; + tilesLayer.useTileColors(useAuthored); +}); + +tilesLayer.draw(() => { + t.clear(); + + const font = tilesLayer.font; + if (!font || font.characters.length === 0) return; + + const cols = 16; + const rows = 8; + const startX = -Math.floor(cols / 2); + const startY = -3; + + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const tileIndex = row * cols + col; + if (tileIndex >= font.characters.length) break; + + t.push(); + t.translate(startX + col, startY + row); + t.char(tileIndex); + const hue = (tileIndex / font.characters.length) * 360; + const r = Math.round(128 + 100 * Math.sin((hue * Math.PI) / 180)); + const g = Math.round(128 + 100 * Math.sin(((hue + 120) * Math.PI) / 180)); + const b = Math.round(128 + 100 * Math.sin(((hue + 240) * Math.PI) / 180)); + t.charColor(r, g, b); + + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + let y = -Math.floor(t.grid.rows / 2) + 3; + const x = -Math.floor(t.grid.cols / 2) + 3; + + drawText('TEXTMODELAYER.USETILECOLORS', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: TILESET COLOR SOURCE', x, y++, [100, 220, 255]); + + if (useAuthored) { + drawText('MODE: AUTHORED COLORS', x, y++, [255, 210, 100]); + drawText('Tile PNG colors show directly.', x, y++, [140, 160, 190]); + } else { + drawText('MODE: RECOLORED', x, y++, [120, 255, 180]); + drawText('charColor palette is applied.', x, y++, [140, 160, 190]); + } + + drawText('------------------------------------', x, y++, [80, 100, 150]); + const remaining = 150 - (t.frameCount % 150); + drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [160, 160, 160]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md index f1bcc5a5..8c4a83ac 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md @@ -29,5 +29,75 @@ readonly [`TextmodeLayer`](../../TextmodeLayer.md)[] ### Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); +const pigments = [ + [243, 114, 92], + [65, 205, 177], + [105, 127, 246], + [244, 196, 94], +]; +const curtains = pigments.map((color) => t.layers.add({ blendMode: 'screen', opacity: 0.64 })); +const labelLayer = t.layers.add(); + +function text(value, x, y, color = [220, 230, 245]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(...color); + t.print(value, x, y); + t.pop(); +} +function put(x, y, glyph, color) { + t.push(); + t.translate(x, y); + t.charColor(...color); + t.char(glyph); + t.point(); + t.pop(); +} +function curtain(index) { + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2), + f = t.frameCount * 0.026; + for (let y = -R; y <= R; y++) { + const spine = Math.sin(y * 0.13 + index * 1.8 + f) * (8 + index * 2) + Math.sin(y * 0.035 - f) * 7; + for (let width = -5; width <= 5; width += 2) { + const x = Math.round(spine + width + Math.sin(y * 0.31 + f * 2) * 2); + if (Math.abs(x) < C - 2 && (y + width + index) % 3 !== 0) + put(x, y, width === 0 ? '|' : ':', pigments[index]); + } + } +} + +curtains.forEach((layer, index) => + layer.draw(() => { + t.clear(); + curtain(index); + }) +); +t.draw(() => { + t.background(7, 8, 22); + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2), + f = t.frameCount * 0.018; + for (let x = -C; x <= C; x += 4) + for (let y = -R; y <= R; y += 3) if ((x * 3 + y) % 11 === 0) put(x, y, '.', [28, 36, 70]); + t.layers.all + .filter((layer) => layer !== labelLayer) + .forEach((layer, index) => { + layer.offset(Math.sin(f + index * 1.7) * 6, Math.cos(f * 1.4 + index) * 2); + layer.opacity(0.44 + 0.32 * (0.5 + 0.5 * Math.sin(f * 3 + index))); + }); +}); +labelLayer.draw(() => { + t.clear(); + const L = -Math.floor(t.grid.cols / 2), + T = -Math.floor(t.grid.rows / 2); + text('LAYERMANAGER.ALL', L + 3, T + 3, [100, 255, 140]); + text('------------------------------------', L + 3, T + 4, [80, 100, 150]); + text('THE WHOLE STACK DRIFTS TOGETHER', L + 3, T + 5, [100, 220, 255]); + text(`LIVE CURTAINS: ${t.layers.all.length - 1}`, L + 3, T + 6, [140, 255, 180]); +}); +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md index b97e659b..fcc6f3d3 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md @@ -35,5 +35,95 @@ The base layer cannot be removed or moved. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const base = t.layers.base; +const overlay = t.layers.add({ blendMode: 'screen', opacity: 0.85 }); +const labelLayer = t.layers.add(); + +base.draw(() => { + t.background(16, 8, 14); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const time = t.frameCount * 0.03; + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const v = Math.abs(Math.sin(x * 0.22) + Math.cos(y * 0.22) + Math.sin((x + y) * 0.08 + time)); + if (v > 0.4) { + const norm = Math.min(1, (v - 0.4) / 1.4); + const idx = Math.floor(norm * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(240, 130 + idx * 10, 50); + t.cellColor(28, 12, 22); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +overlay.draw(() => { + t.clear(); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const angle = t.frameCount * 0.025; + const cosA = Math.cos(angle); + const sinA = Math.sin(angle); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const d = Math.abs(-sinA * x + cosA * y); + if (d < 1.5) { + const intensity = 1 - d / 1.5; + const idx = Math.floor(intensity * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(40, 240, 160); + t.cellColor(8, 45, 30); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('LAYERMANAGER.BASE', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: ACCESSING BASE LAYER', x, y++); + t.charColor(140, 160, 190); + t.print('Accesses base layer via t.layers.base.', x, y++); + t.print('Base layer draws below user overlays.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('BASE LAYER ACTIVE: YES', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md index 032c7efb..15829987 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md @@ -32,5 +32,102 @@ and any user-created layer via [TextmodeLayer.filter](../../TextmodeLayer/method ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const filteredLayer = t.layers.add({ blendMode: 'screen', opacity: 0.8 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +t.setup(async () => { + await t.layers.filters.register( + 'ripple', + `#version 300 es +precision highp float; +uniform sampler2D u_texture; +uniform float u_time; +uniform float u_amount; +in vec2 v_uv; +out vec4 fragColor; +void main() { + float d = length(v_uv - 0.5); + float w = sin(d * 8.0 - u_time) * u_amount; + vec2 uv = v_uv + vec2(w * cos(d * 3.0), w * sin(d * 3.0)); + fragColor = texture(u_texture, clamp(uv, 0.0, 1.0)); +}`, + { u_time: ['time', 0], u_amount: ['amount', 0.025] } + ); +}); + +t.draw(() => { + t.background(6, 10, 22); + + const tc = t.frameCount * 0.022; + for (let i = 0; i < 75; i++) { + const p = (i / 75) * Math.PI * 2; + const r = 3 + 6 * ((i % 8) / 8) + Math.sin(tc + i * 0.15) * 1.2; + const a = p + tc * 0.35 * ((i % 3) - 1); + const x = Math.round(Math.cos(a) * r * 1.5); + const y = Math.round(Math.sin(a) * r); + + t.push(); + t.translate(x, y); + t.charColor(30 + i * 0.8, 60 + i * 0.4, 110 + i * 0.3); + t.char('.'); + t.point(); + t.pop(); + } +}); + +filteredLayer.draw(() => { + t.clear(); + + const tc = t.frameCount * 0.028; + for (let i = 0; i < 60; i++) { + const p = (i / 60) * Math.PI * 2; + const r = 2 + 4 * ((i % 6) / 6) + Math.sin(tc * 0.8 + i * 0.22) * 1; + const a = p - tc * 0.5 * ((i % 3) + 1); + const x = Math.round(Math.cos(a) * r * 1.5); + const y = Math.round(Math.sin(a) * r); + const hue = Math.sin(a + tc) * 0.4 + 0.6; + + t.push(); + t.translate(x, y); + t.charColor(200 + hue * 55, 100 + hue * 70, 50 + hue * 40); + t.char('*'); + t.point(); + t.pop(); + } + + filteredLayer.filter('ripple', { time: tc * 2, amount: 0.022 }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + + drawText('LAYERMANAGER.FILTERS', left + 3, y++, [100, 255, 140]); + drawText('------------------------------------', left + 3, y++, [80, 100, 150]); + drawText('CONCEPT: GLOBAL FILTER MANAGER', left + 3, y++, [100, 220, 255]); + drawText('Registers a custom ripple filter.', left + 3, y++, [140, 160, 190]); + drawText('FILTER: ripple', left + 3, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md index ca526f7b..6554916f 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md @@ -32,5 +32,97 @@ that will receive the current frame's composited result. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; +const waveLayer = t.layers.add({ blendMode: 'screen' }); +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(5, 10, 24); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.04; + + const lissX = Math.sin(tm * 1.3) * (hw * 0.6); + const lissY = Math.cos(tm * 0.9) * (hh * 0.6); + + for (let y = -hh; y <= hh; y++) { + for (let x = -hw; x <= hw; x++) { + const dist = Math.hypot(x - lissX, y - lissY); + const wave = (Math.sin(dist * 0.35 - tm * 2) + 1) * 0.5; + + if (wave > 0.5) { + const idx = Math.floor(((wave - 0.5) / 0.5) * (RAMP.length - 1)); + t.push(); + t.translate(x, y); + t.charColor(0, Math.floor(120 + wave * 135), 245); + t.cellColor(2, 12, 35); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +}); + +waveLayer.draw(() => { + t.clear(); + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const tm = t.frameCount * 0.03; + + for (let y = -hh; y <= hh; y += 2) { + for (let x = -hw; x <= hw; x += 2) { + const gridHarmonic = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 - tm); + if (gridHarmonic > 0.4) { + t.push(); + t.translate(x, y); + t.charColor(255, 130, 40); + t.char('+'); + t.point(); + t.pop(); + } + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + const fb = t.layers.resultFramebuffer; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('LAYERMANAGER.RESULTFRAMEBUFFER', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: OSCILLOSCOPE FEEDBACK LENS', x, y++); + t.charColor(140, 160, 190); + t.print('Inspects composited WebGL framebuffer.', x, y++); + t.print('Reads pixel render target bounds.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + if (fb) { + t.charColor(255, 180, 40); + t.print(`FB BOUNDS: ${fb.width}x${fb.height} PX`, x, y++); + } + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md index 1ec5fc06..81dcf6bf 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md @@ -38,5 +38,94 @@ The created layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const RAMP = ' .:-=+*#%@'; + +const layer1 = t.layers.add({ blendMode: 'screen', opacity: 0.85 }); +const layer2 = t.layers.add({ blendMode: 'additive', opacity: 0.75 }); +const labelLayer = t.layers.add(); + +function drawField(fn, fg, bg, minV = 0.3) { + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + for (let y = -hh; y <= hh; y += 1) { + for (let x = -hw; x <= hw; x += 1) { + const v = fn(x, y); + if (v > minV) { + const idx = Math.min(RAMP.length - 1, Math.floor(((v - minV) / (1 - minV)) * RAMP.length)); + t.push(); + t.translate(x, y); + t.charColor(fg[0], fg[1], fg[2]); + t.cellColor(bg[0], bg[1], bg[2]); + t.char(RAMP[idx]); + t.point(); + t.pop(); + } + } + } +} + +t.draw(() => { + t.background(6, 10, 22); + const tm = t.frameCount * 0.02; + const f = (x, y) => (Math.sin(x * 0.08 + tm) + Math.cos(y * 0.1 + tm)) * 0.5 + 0.5; + drawField(f, [40, 70, 110], [10, 16, 32], 0.4); +}); + +layer1.draw(() => { + t.clear(); + const tm = t.frameCount * 0.03; + const f = (x, y) => Math.sin(x * 0.1 + y * 0.08 + tm) * Math.cos(x * 0.08 - y * 0.12 + tm * 0.8); + drawField(f, [240, 150, 40], [60, 30, 8], 0.25); +}); + +layer2.draw(() => { + t.clear(); + const tm = t.frameCount * 0.04; + const hw = Math.floor(t.grid.cols / 2); + const hh = Math.floor(t.grid.rows / 2); + const cx = Math.cos(tm) * (hw * 0.4); + const cy = Math.sin(tm * 0.8) * (hh * 0.4); + const f = (x, y) => + (Math.sin(Math.hypot(x - cx, y - cy) * 0.35 - tm * 1.5) + + Math.sin(Math.hypot(x + cx, y + cy) * 0.35 - tm * 1.5)) * + 0.5; + drawField(f, [40, 220, 200], [8, 50, 45], 0.3); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('LAYERMANAGER.ADD', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: GENERATIVE LAYERED FIELDS', x, y++); + t.charColor(140, 160, 190); + t.print('Adds user layers to composite fields.', x, y++); + t.print('Layers blend screen & additive passes.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print('USER LAYERS ADDED: 2', x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md index 1d55b8e6..4c5c0098 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md @@ -29,5 +29,102 @@ The base layer is not affected by this operation. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const REGIMES = [ + { name: 'RAIN', glyph: '|', rise: false, vel: 0.9, sway: 0, tint: [150, 190, 255] }, + { name: 'EMBERS', glyph: '*', rise: true, vel: 0.3, sway: 2, tint: [255, 170, 60] }, + { name: 'SNOW', glyph: '*', rise: false, vel: 0.14, sway: 2, tint: [225, 235, 255] }, +]; +let mode = 0; +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} +function put(x, y, glyph, rgb) { + t.push(); + t.translate(x, y); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.char(glyph); + t.point(); + t.pop(); +} +const hash = (x, y) => Math.abs(Math.sin(x * 127.1 + y * 311.7) * 43758.5453) % 1; + +function drawHud() { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('LAYERMANAGER.CLEAR', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: WIPE USER LAYERS', x, y++, [100, 220, 255]); + drawText('clear() rebuilds the stack.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`REGIME: ${REGIMES[mode % 3].name}`, x, y++, [140, 255, 180]); +} + +function weatherLayer(near) { + const layer = t.layers.add({ blendMode: t.BLEND_ADDITIVE, opacity: near ? 0.9 : 0.5 }); + + layer.draw(() => { + t.clear(); + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + const rg = REGIMES[mode % REGIMES.length]; + const rgb = near ? rg.tint : rg.tint.map((c) => Math.floor(c * 0.5)); + const f = t.frameCount; + + for (let i = 0; i < (near ? 34 : 60); i++) { + const h = hash(i, near ? 3 : 7); + const travel = (h * t.grid.rows + f * rg.vel * (0.6 + h) * (near ? 1 : 0.6)) % t.grid.rows; + const x = Math.floor(hash(i, 11) * t.grid.cols) - C + Math.round(Math.sin(f * 0.03 + i) * rg.sway); + const ground = R * 0.45 + Math.sin(x * 0.05 + 1) * 3 + Math.sin(x * 0.13) * 2; + const y = Math.floor(rg.rise ? ground - travel : Math.min(travel - R, ground)); + put(x, y, near ? rg.glyph : '.', rgb); + } + }); +} + +function rebuild() { + t.layers.clear(); + mode++; + weatherLayer(false); + weatherLayer(true); + t.layers.add().draw(drawHud); +} + +t.setup(() => rebuild()); + +t.draw(() => { + t.background(4, 8, 12); + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + + for (let x = -C; x < C; x++) { + const ridge = R * 0.45 + Math.sin(x * 0.05 + 1) * 3 + Math.sin(x * 0.13) * 2; + for (let y = -R; y < R; y++) { + const h = hash(x, y); + if (h > 0.986 && y < ridge) put(x, y, h > 0.994 ? '+' : '.', [70, 90, 110]); + if (y > ridge) put(x, y, y - ridge > 4 ? '#' : ':', [16, 34, 30]); + } + } + + if (t.frameCount % 240 === 0) rebuild(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md index 0af38c22..26411fc1 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md @@ -34,5 +34,100 @@ Move a user-created layer to a new index in the stack. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} + +const layer1 = t.layers.add(); +const layer2 = t.layers.add({ blendMode: 'screen', opacity: 0.55 }); +const layer3 = t.layers.add({ blendMode: 'additive', opacity: 0.4 }); +const labelLayer = t.layers.add(); + +layer1.draw(() => { + t.clear(); + + for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { + for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { + const v = Math.sin(x * 0.12 + t.frameCount * 0.02) * Math.cos(y * 0.14 + t.frameCount * 0.014); + if (Math.abs(v) < 0.12) continue; + + t.push(); + t.translate(x, y); + t.charColor(180 + v * 75, 80 + v * 80, 20 + v * 40); + t.char(v > 0.5 ? '@' : v > 0.25 ? '+' : '.'); + t.point(); + t.pop(); + } + } +}); + +layer2.draw(() => { + t.clear(); + + for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { + for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { + const v = Math.sin((x + y) * 0.11 + t.frameCount * 0.022) * Math.sin((x - y) * 0.11 + t.frameCount * 0.016); + if (Math.abs(v) < 0.1) continue; + + t.push(); + t.translate(x, y); + t.charColor(40 + v * 60, 160 + v * 95, 120 + v * 55); + t.char(v > 0.5 ? '@' : v > 0.25 ? '+' : '.'); + t.point(); + t.pop(); + } + } +}); + +layer3.draw(() => { + t.clear(); + + for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { + for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { + const d = Math.sqrt(x * x * 0.9 + y * y) * 0.16; + const v = Math.sin(d - t.frameCount * 0.025) / (d * 0.2 + 1); + if (v < 0.08) continue; + + t.push(); + t.translate(x, y); + t.charColor(120 + v * 100, 50 + v * 60, 200 + v * 55); + t.char(v > 0.4 ? '@' : v > 0.2 ? '+' : '.'); + t.point(); + t.pop(); + } + } +}); + +t.draw(() => { + t.background(6, 10, 22); + if (t.frameCount % 75 === 0 && t.layers.all.length > 2) t.layers.move(t.layers.all[0], t.layers.all.length - 2); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2), + top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + + drawText('LAYERMANAGER.MOVE', left + 3, y++, [100, 255, 140]); + drawText('CONCEPT: MOVE LAYER INDEX', left + 3, y++, [100, 220, 255]); + drawText('nrml / screen 0.55 / add 0.4', left + 3, y++, [140, 190, 255]); + drawText('Bottom layer rotates to the top.', left + 3, y++, [140, 160, 190]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md index b7c86788..453f3f6c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md @@ -33,5 +33,100 @@ Remove and dispose a user-created layer. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const SPAWNS = [ + [-16, -5], + [12, -8], + [3, 5], + [-7, 9], + [17, 3], +]; +const rings = []; +const labelLayer = t.layers.add(); +let spawns = 0; + +function drawText(text, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(text, x, y); + t.pop(); +} +function put(x, y, glyph, rgb) { + t.push(); + t.translate(x, y); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.char(glyph); + t.point(); + t.pop(); +} + +function spawnRing() { + const [cx, cy] = SPAWNS[spawns++ % SPAWNS.length]; + const layer = t.layers.add({ blendMode: t.BLEND_ADDITIVE }); + const born = t.frameCount; + + layer.draw(() => { + t.clear(); + const age = t.frameCount - born; + const r = 1 + age * 0.16; + + for (let a = 0; a < Math.PI * 2; a += 0.09) { + const ca = Math.cos(a), + sa = Math.sin(a); + put(cx + Math.round(ca * r * 2.1), cy + Math.round(sa * r), '.', [120, 220, 255]); + if (age > 20) put(cx + Math.round(ca * r * 1.15), cy + Math.round(sa * r * 0.55), '.', [70, 140, 190]); + } + }); + + rings.push({ layer, born }); + t.layers.move(labelLayer, Number.MAX_SAFE_INTEGER); +} + +t.draw(() => { + t.background(3, 7, 18); + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + + for (let x = -C; x < C; x += 3) + for (let y = -R; y < R; y += 2) put(x, y, '.', [10, 18 + (y / R) * 14, 34 + (y / R) * 22]); + + if (t.frameCount % 34 === 0) spawnRing(); + + for (let i = rings.length - 1; i >= 0; i--) { + const age = t.frameCount - rings[i].born; + rings[i].layer.opacity(Math.max(0, 1 - age / 90)); + + if (age > 90) { + t.layers.remove(rings[i].layer); + rings.splice(i, 1); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('LAYERMANAGER.REMOVE', x, y++, [100, 255, 140]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText('CONCEPT: DISPOSE LAYERS', x, y++, [100, 220, 255]); + drawText('Dead ripples are removed.', x, y++, [140, 160, 190]); + drawText('------------------------------------', x, y++, [80, 100, 150]); + drawText(`ACTIVE RINGS: ${rings.length}`, x, y++, [140, 255, 180]); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md index a0f3b693..d0818598 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md @@ -34,5 +34,102 @@ Swap two user-created layers. ## Example - +```javascript +const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); + +const RAMP = ' .:-=+*#%@'; +const warm = t.layers.add({ blendMode: 'normal' }); +const cool = t.layers.add({ blendMode: 'normal' }); +const label = t.layers.add(); + +function text(value, x, y, rgb = [255, 255, 255]) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(rgb[0], rgb[1], rgb[2]); + t.print(value, x, y); + t.pop(); +} +function put(x, y, glyph, fg, bg) { + t.push(); + t.translate(x, y); + t.charColor(fg[0], fg[1], fg[2]); + if (bg) t.cellColor(bg[0], bg[1], bg[2]); + t.char(glyph); + t.point(); + t.pop(); +} +function paint(fn, threshold, fgBase, bgBase) { + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + for (let y = -R; y <= R; y++) + for (let x = -C; x <= C; x++) { + const v = fn(x, y); + if (v < threshold) continue; + const idx = Math.min(RAMP.length - 1, Math.floor(v * (RAMP.length + 1))); + put( + x, + y, + RAMP[idx], + [Math.floor(fgBase[0] * v), Math.floor(fgBase[1] * v), Math.floor(fgBase[2] * v)], + [Math.floor(bgBase[0] * v), Math.floor(bgBase[1] * v), Math.floor(bgBase[2] * v)] + ); + } +} + +warm.draw(() => { + t.clear(); + const f = t.frameCount * 0.012; + paint( + (x, y) => + 1 - Math.abs((((x + y + Math.sin(x * 0.07 + f) * 4 + Math.cos(y * 0.06 + f * 0.7) * 4) * 0.16) % 2) - 1), + 0.36, + [235, 130, 35], + [35, 12, 4] + ); +}); + +cool.draw(() => { + t.clear(); + const f = t.frameCount * 0.011; + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + paint( + (x, y) => { + let best = 0; + for (let i = 0; i < 7; i++) { + const sx = Math.sin(i * 1.9 + f * 0.6) * C * 0.5; + const sy = Math.cos(i * 1.5 + f * 0.45) * R * 0.5; + best = Math.max(best, Math.exp(-Math.hypot(x - sx, y - sy) * 0.16)); + } + return best; + }, + 0.38, + [60, 175, 240], + [4, 24, 42] + ); +}); + +t.draw(() => { + t.background(4, 7, 18); + const C = Math.floor(t.grid.cols / 2), + R = Math.floor(t.grid.rows / 2); + for (let x = -C; x <= C; x += 4) + for (let y = -R; y <= R; y += 3) if ((x * 7 + y * 13) % 19 === 0) put(x, y, '.', [16, 24, 45]); + if (t.frameCount % 120 === 0) t.layers.swap(warm, cool); +}); + +label.draw(() => { + t.clear(); + const L = -Math.floor(t.grid.cols / 2), + T = -Math.floor(t.grid.rows / 2); + let y = T + 3; + const warmTop = Math.floor(t.frameCount / 120) % 2 === 0; + text('LAYERMANAGER.SWAP', L + 3, y++, [100, 255, 140]); + text('------------------------------------', L + 3, y++, [80, 100, 150]); + text('Normal blend: top occludes below.', L + 3, y++, [100, 220, 255]); + text(warmTop ? 'TOP: WARM FIELD' : 'TOP: COOL ORBS', L + 3, y++, [140, 255, 180]); +}); + +t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); +``` diff --git a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md index a9e3c54c..a778101a 100644 --- a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md +++ b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md @@ -42,7 +42,82 @@ that should get brighter as animated layers overlap. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_ADDITIVE; +const modeName = 'BLEND_ADDITIVE'; +const accent = [255, 100, 80]; +const base = [28, 80, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.78 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(4, 8, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.17 + y * 0.11 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : ':'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(2, 6, 16); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 16; i++) { + const angle = i * 22.5 + ring * 11 + t.frameCount * 1.6; + const radius = 4 + ring * 3.8 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '*' : '@'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 10, 12); + t.rect(3, 2 + (i % 2)); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_ADDITIVE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ADDITIVE LIGHT', x, y++, 100, 220, 255); + drawText('Overlaps grow brighter.', x, y++, 140, 160, 190); + drawText('Good for sparks and glow.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -59,7 +134,82 @@ shapes that should compress color toward black. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_COLOR_BURN; +const modeName = 'BLEND_COLOR_BURN'; +const accent = [120, 50, 70]; +const base = [220, 170, 110]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.034; + t.background(50, 34, 22); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.13 - y * 0.15 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '%' : '+'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(52, 28, 16); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 18 - t.frameCount * 1.2; + const radius = 5 + ring * 3.8 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '#' : 'X'); + t.charColor(...accent); + t.cellColor(24 + ring * 10, 5, 10 + ring * 6); + t.rect(4, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_COLOR_BURN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: BURN SHADOWS', x, y++, 100, 220, 255); + drawText('Color compresses darker.', x, y++, 140, 160, 190); + drawText('Motion leaves dense marks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -76,7 +226,82 @@ should push quickly toward white. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_COLOR_DODGE; +const modeName = 'BLEND_COLOR_DODGE'; +const accent = [255, 245, 170]; +const base = [42, 80, 130]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.72 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.038; + t.background(4, 10, 24); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.15 + y * 0.14 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(3, 8, 20); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 19 + t.frameCount * 1.8; + const radius = 4 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '*' : '@'); + t.charColor(...accent); + t.cellColor(45 + ring * 22, 42 + ring * 16, 16); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_COLOR_DODGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DODGE FLARES', x, y++, 100, 220, 255); + drawText('Small marks bloom fast.', x, y++, 140, 160, 190); + drawText('Highlights push to white.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -93,7 +318,82 @@ existing composition. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_DARKEN; +const modeName = 'BLEND_DARKEN'; +const accent = [90, 110, 170]; +const base = [220, 190, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.03; + t.background(46, 40, 25); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.16 - y * 0.1 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(48, 38, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 19 + t.frameCount; + const radius = 5 + ring * 3.8 + Math.cos(time + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time * 1.5 + i) * 2); + t.char(ring % 2 ? '%' : '#'); + t.charColor(...accent); + t.cellColor(10 + ring * 7, 12 + ring * 8, 30 + ring * 14); + t.rect(4, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_DARKEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: DARKER CHANNELS', x, y++, 100, 220, 255); + drawText('Only darker color wins.', x, y++, 140, 160, 190); + drawText('Moving marks add shade.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -110,7 +410,82 @@ overlaps that reveal contrast where colors diverge. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_DIFFERENCE; +const modeName = 'BLEND_DIFFERENCE'; +const accent = [255, 255, 255]; +const base = [70, 180, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.9 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.036; + t.background(8, 16, 24); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.17 + y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '-'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(4, 12, 20); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 29 + t.frameCount * 1.5; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '@' : '#'); + t.charColor(...accent); + t.cellColor(70, 70, 70); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_DIFFERENCE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT BY DISTANCE', x, y++, 100, 220, 255); + drawText('Unlike colors spark edges.', x, y++, 140, 160, 190); + drawText('Overlaps flip the field.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -127,7 +502,82 @@ overlays that should shift color without the full edge of difference. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_EXCLUSION; +const modeName = 'BLEND_EXCLUSION'; +const accent = [230, 230, 255]; +const base = [120, 100, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.033; + t.background(16, 14, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.16 - y * 0.13 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 32, base[2]); + t.cellColor(10, 8, 24); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 25 - t.frameCount * 1.25; + const radius = 5 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(45 + ring * 12, 45 + ring * 12, 68); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_EXCLUSION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOFT INVERSION', x, y++, 100, 220, 255); + drawText('Difference with less bite.', x, y++, 140, 160, 190); + drawText('Color shifts stay muted.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -144,7 +594,82 @@ marks that should strongly reshape contrast. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_HARD_LIGHT; +const modeName = 'BLEND_HARD_LIGHT'; +const accent = [255, 220, 70]; +const base = [65, 75, 150]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.04; + t.background(10, 12, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.18 - y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '#' : ':'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(8, 8, 24); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 27 - t.frameCount * 1.6; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.4; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? 'X' : '#'); + t.charColor(...accent); + t.cellColor(45 + ring * 20, 38 + ring * 12, 6); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_HARD_LIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: HARD CONTRAST', x, y++, 100, 220, 255); + drawText('The top layer drives punch.', x, y++, 140, 160, 190); + drawText('Edges become more graphic.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -161,7 +686,82 @@ existing composition. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_LIGHTEN; +const modeName = 'BLEND_LIGHTEN'; +const accent = [255, 230, 130]; +const base = [40, 70, 105]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.034; + t.background(8, 15, 28); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.13 + y * 0.18 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? ':' : '.'); + t.charColor(base[0], base[1] + wave * 25, base[2]); + t.cellColor(5, 10, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 13 - t.frameCount * 1.1; + const radius = 4 + ring * 4 + Math.sin(time + i) * 2.2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time * 1.6 + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(45 + ring * 15, 42 + ring * 10, 18); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_LIGHTEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LIGHTER CHANNELS', x, y++, 100, 220, 255); + drawText('Only brighter color wins.', x, y++, 140, 160, 190); + drawText('Moving marks reveal light.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -178,7 +778,82 @@ shadow-like patterns that preserve underlying contrast. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_MULTIPLY; +const modeName = 'BLEND_MULTIPLY'; +const accent = [130, 180, 255]; +const base = [220, 150, 90]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.032; + t.background(42, 30, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.12 - y * 0.16 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '%' : '+'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(50, 28, 12); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 20; i++) { + const angle = i * 18 + ring * 14 - t.frameCount * 1.1; + const radius = 6 + ring * 4 + Math.cos(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + ring) * 2); + t.char(ring % 2 ? 'X' : '#'); + t.charColor(...accent); + t.cellColor(12, 25 + ring * 20, 58 + ring * 12); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_MULTIPLY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: MULTIPLY SHADE', x, y++, 100, 220, 255); + drawText('Overlap darkens the base.', x, y++, 140, 160, 190); + drawText('Color stays tied to below.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -195,7 +870,83 @@ controlling how much of the layer covers the layers below it. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_NORMAL; +const modeName = 'BLEND_NORMAL'; +const accent = [250, 180, 90]; +const base = [35, 70, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.035; + t.background(8, 10, 22); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.18 + y * 0.13 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '+' : '.'); + t.charColor(base[0] + wave * 30, base[1] + 20, base[2]); + t.cellColor(4, 8, 18); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 17 + t.frameCount * (1.2 + ring * 0.2); + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.rotateZ(-angle * 0.5); + t.char(ring % 2 ? '@' : '#'); + t.charColor(...accent); + t.cellColor(20 + ring * 18, 16, 32 + ring * 12); + t.rect(3 + (i % 2), 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_NORMAL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: NORMAL BLEND', x, y++, 100, 220, 255); + drawText('Animated layer covers below.', x, y++, 140, 160, 190); + drawText('Opacity controls the mix.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -212,7 +963,82 @@ highlights in one pass. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_OVERLAY; +const modeName = 'BLEND_OVERLAY'; +const accent = [255, 90, 190]; +const base = [80, 125, 190]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.83 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.037; + t.background(10, 18, 32); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.14 + y * 0.12 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : '-'); + t.charColor(base[0], base[1] + wave * 35, base[2]); + t.cellColor(8, 14, 26); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 21 + t.frameCount * 1.35; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.sin(time + i) * 2); + t.char(ring % 2 ? '@' : '%'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 10, 42 + ring * 12); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_OVERLAY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CONTRAST BOOST', x, y++, 100, 220, 255); + drawText('Dark stays deep, light lifts.', x, y++, 140, 160, 190); + drawText('Good for graphic masks.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -229,7 +1055,82 @@ areas while preserving highlight detail. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SCREEN; +const modeName = 'BLEND_SCREEN'; +const accent = [100, 220, 255]; +const base = [85, 45, 120]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.8 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.036; + t.background(12, 8, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.2 + y * 0.08 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(8, 4, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 23 + t.frameCount * 1.3; + const radius = 6 + ring * 3.5 + Math.sin(time + i) * 2; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time * 1.4 + i) * 2); + t.char(ring % 2 ? '*' : '+'); + t.charColor(...accent); + t.cellColor(5, 30 + ring * 10, 45 + ring * 20); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SCREEN', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SCREEN LIGHT', x, y++, 100, 220, 255); + drawText('Dark areas lift upward.', x, y++, 140, 160, 190); + drawText('Highlights stay open.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -246,7 +1147,82 @@ animated texture that should stay subtle. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SOFT_LIGHT; +const modeName = 'BLEND_SOFT_LIGHT'; +const accent = [255, 170, 150]; +const base = [70, 120, 160]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.029; + t.background(12, 20, 30); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.12 + y * 0.15 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '~' : '.'); + t.charColor(base[0], base[1] + wave * 28, base[2]); + t.cellColor(8, 14, 22); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 5; ring++) { + for (let i = 0; i < 14; i++) { + const angle = i * 25.7 + ring * 16 + t.frameCount * 0.9; + const radius = 5 + ring * 3.5 + Math.sin(time + i) * 1.5; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '+' : '*'); + t.charColor(...accent); + t.cellColor(28 + ring * 14, 20 + ring * 10, 30); + t.rect(3, 3); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SOFT_LIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOFT CONTRAST', x, y++, 100, 220, 255); + drawText('Texture changes gently.', x, y++, 140, 160, 190); + drawText('Useful for atmosphere.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` *** @@ -263,4 +1239,79 @@ that remove brightness from the composite. #### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const mode = t.BLEND_SUBTRACT; +const modeName = 'BLEND_SUBTRACT'; +const accent = [180, 230, 255]; +const base = [210, 120, 70]; +const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); +const labelLayer = t.layers.add(); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + const time = t.frameCount * 0.033; + t.background(48, 28, 18); + const { cols, rows } = t.grid; + for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { + for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { + const wave = Math.sin(x * 0.11 + y * 0.19 + time); + t.push(); + t.translate(x, y); + t.char(wave > 0 ? '=' : '+'); + t.charColor(base[0], base[1] + wave * 30, base[2]); + t.cellColor(55, 24, 10); + t.rect(2, 2); + t.pop(); + } + } + blendLayer.draw(() => { + t.clear(); + for (let ring = 0; ring < 4; ring++) { + for (let i = 0; i < 18; i++) { + const angle = i * 20 + ring * 15 - t.frameCount * 1.4; + const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.8; + t.push(); + t.rotateZ(angle); + t.translate(radius, Math.cos(time + i) * 2); + t.char(ring % 2 ? '/' : '\\'); + t.charColor(...accent); + t.cellColor(35 + ring * 18, 45 + ring * 12, 58); + t.rect(4, 2); + t.pop(); + } + } + }); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + drawText('TEXTMODIFIER.BLEND_SUBTRACT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUBTRACT CUTS', x, y++, 100, 220, 255); + drawText('The top layer removes light.', x, y++, 140, 160, 190); + drawText('Bright marks carve paths.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage.md b/api/textmode.js/namespaces/media/classes/TextmodeImage.md index 0e9a0441..aece6168 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage.md @@ -22,7 +22,87 @@ and configure conversion through inherited chainable methods. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let image = null; + +function createReactionCanvas() { + const canvas = document.createElement('canvas'); + canvas.width = 64; + canvas.height = 48; + const ctx = canvas.getContext('2d'); + + const imgData = ctx.createImageData(64, 48); + const data = imgData.data; + + for (let y = 0; y < 48; y++) { + for (let x = 0; x < 64; x++) { + const idx = (y * 64 + x) * 4; + const v = Math.sin(x * 0.15) * Math.cos(y * 0.15) + Math.sin(x * 0.3 + y * 0.2); + const norm = (v + 2) / 4; + + data[idx] = Math.floor(15 + norm * 240); + data[idx + 1] = Math.floor(23 + norm * 160); + data[idx + 2] = Math.floor(42 + norm * 210); + data[idx + 3] = 255; + } + } + ctx.putImageData(imgData, 0, 0); + return canvas.toDataURL(); +} + +t.setup(async () => { + image = await t.loadImage(createReactionCanvas()); + image.characters(' .:-=+*#%@'); + image.cellColorMode('sampled'); +}); + +t.draw(() => { + t.background(15, 23, 42); + if (!image) return; + + t.push(); + t.rotateZ(Math.sin(t.frameCount * 0.03) * 64); + t.image(image, Math.floor(t.grid.cols * 0.6), Math.floor(t.grid.rows * 0.6)); + t.pop(); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('TEXTMODEIMAGE.CREATION', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: REACTION CANV CONVERTER', x, y++); + t.charColor(140, 160, 190); + t.print('Loads HTML canvas data into image.', x, y++); + t.print('Converts source pixels into cells.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(245, 158, 11); + t.print(`IMAGE SIZE: ${image ? image.width : 0}x${image ? image.height : 0} PX`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Extends diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md index 54cdfbc2..4161bd8e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md @@ -29,7 +29,81 @@ Ideal draw height in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.height : 0; + drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md index cb01d369..be644b34 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md @@ -29,7 +29,81 @@ Original source height in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.originalHeight : 0; + drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md index bec7a609..54a3c860 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md @@ -29,7 +29,81 @@ Original source width in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.originalWidth : 0; + drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md index a56d7890..6787082a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md @@ -29,7 +29,81 @@ WebGL texture backing this source. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = source && source.texture ? 'READY' : 'WAIT'; + drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md index d1c72b5a..624b7bbc 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md @@ -29,7 +29,81 @@ Ideal draw width in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.width : 0; + drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md index b93ec415..c4764e59 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md @@ -42,7 +42,97 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let sourceA, sourceB; + +function createTransparentCanvas() { + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + const ctx = canvas.getContext('2d'); + if (!ctx) return canvas; + + ctx.clearRect(0, 0, 128, 128); + ctx.lineWidth = 10; + ctx.strokeStyle = '#ffffff'; + ctx.strokeRect(20, 20, 88, 88); + + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(64, 64, 30, 0, Math.PI * 2); + ctx.fill(); + + return canvas; +} + +t.setup(() => { + const canvas = createTransparentCanvas(); + + sourceA = t.createTexture(canvas); + sourceA.characters(' .:-=+*#%@'); + + sourceB = t.createTexture(canvas); + sourceB.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (!sourceA || !sourceB) return; + + const time = t.frameCount * 0.05; + const pulse = 0.5 + 0.5 * Math.sin(time); + sourceB.background(pulse * 255, 100, 255 - pulse * 155); + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); + drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); + drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md index efc1e389..7690e0a3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md @@ -36,7 +36,92 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const ranges = [ + { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, + { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, + { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, +]; + +let rangeSources = []; + +function drawRangeSource(source, x, y, width, height) { + t.push(); + t.translate(x, y); + t.image(source, width, height); + t.pop(); +} + +t.setup(async () => { + rangeSources = await Promise.all( + ranges.map(async (range) => { + const source = await t.loadImage(IMAGE_URL); + source.brightnessRange(range.start, range.end); + source.characters(range.characters); + source.charColorMode('fixed'); + source.charColor(range.charColor); + source.cellColorMode('fixed'); + source.cellColor('#00000000'); + return source; + }) + ); +}); + +t.draw(() => { + t.background(4, 7, 18); + if (rangeSources.length === 0) return; + + const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); + const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); + const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); + const totalWidth = panelWidth * 3 + gap * 2; + const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); + const y = -1; + + for (let i = 0; i < rangeSources.length; i++) { + const x = startX + i * (panelWidth + gap); + drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); + drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); + drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); + drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md index 0471d8aa..fe5849d5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md @@ -42,7 +42,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let red = 40; +let blue = 80; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed').charColor(255); + techSource.cellColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + red = Math.round(40 + 40 * Math.sin(time)); + blue = Math.round(80 + 40 * Math.cos(time * 0.7)); + + techSource.cellColor(red, 40, blue); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md index 2eb2ccb0..003d6d26 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.cellColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.cellColorMode('fixed').cellColor(20, 30, 60); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md index f4b2f769..c7049197 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md @@ -42,7 +42,70 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let r = 150; +let g = 150; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + r = Math.round(150 + 105 * Math.sin(time)); + g = Math.round(150 + 105 * Math.cos(time * 0.7)); + + techSource.charColor(r, g, 100); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md index c5ac1727..e053d0e8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.charColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.charColorMode('fixed').charColor(140, 255, 180); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md index 61fe787d..c9e77697 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let pointerSource = null; + +t.setup(async () => { + pointerSource = await t.loadImage(IMAGE_URL); + pointerSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!pointerSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + pointerSource.charRotation(0); + t.image(pointerSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + pointerSource.charRotation(90); + t.image(pointerSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); + drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md index fab2da67..7b415ba9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md @@ -35,7 +35,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.characters(' .oO@'); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const chars = ' .oO@'; + drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md index b3e62ab4..1335ff12 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md @@ -31,7 +31,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); + source.clearConversions(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STACK: CLEARED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md index de1edc0c..5b2d5e5f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md @@ -35,7 +35,59 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let source = null; + +t.setup(async () => { + source = await t.loadImage(IMAGE_URL); + source.conversionMode('brightness'); + source.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(4, 7, 18); + t.background(0); + if (!source) return; + + t.image(source, source.width, source.height); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md index 928bb553..a82eeaaa 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md @@ -35,7 +35,101 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + Object.assign(canvas, { width: 128, height: 80 }); + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 128, 80); + gradient.addColorStop(0, '#020617'); + gradient.addColorStop(0.45, '#0ea5e9'); + gradient.addColorStop(1, '#f8fafc'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 128, 80); + ctx.fillStyle = '#f97316'; + ctx.fillRect(15, 16, 34, 44); + ctx.fillStyle = '#fde68a'; + ctx.fillRect(78, 22, 34, 34); + return canvas.toDataURL(); +} + +function configureSource(source) { + source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); +} + +function brightnessPass(start, end, characters, charColor) { + return { + mode: 'brightness', + brightnessStart: start, + brightnessEnd: end, + characters, + charColorMode: 'fixed', + charColor, + }; +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([ + brightnessPass(0, 84, ' .:', '#38bdf8'), + brightnessPass(85, 169, '-=+', '#facc15'), + brightnessPass(170, 255, '*#@', '#f8fafc'), + ]); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + if (!source) return; + + const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); + const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); + const y = Math.floor(t.grid.rows * 0.12); + t.push(); + t.translate(0, y); + t.image(source, width, height); + t.pop(); + drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); + drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('PASSES: 3', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md index 8583dccb..98093d75 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md @@ -27,7 +27,89 @@ Dispose of the resource and free associated WebGL textures. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.mouseClicked(() => { + if (source && !disposed) { + source.dispose(); + disposed = true; + } +}); + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = disposed ? 'Disposed' : 'Active'; + drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md index 3a0a8391..b0fd43b2 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipX(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipX(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); + drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md index e94aca69..fb9a036c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipY(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipY(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); + drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md index 4edeb65f..ce4a12ec 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let gradientSource = null; + +t.setup(async () => { + gradientSource = await t.loadImage(IMAGE_URL); + gradientSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!gradientSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + gradientSource.invert(false); + t.image(gradientSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + gradientSource.invert(true); + t.image(gradientSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); + drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md index c4cd5613..d0595354 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md @@ -29,5 +29,78 @@ Ideal draw height in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.height : 0; + drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md index 8eef9b22..aa6b2559 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md @@ -29,5 +29,78 @@ Original source height in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.originalHeight : 0; + drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md index 8c964474..435059eb 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md @@ -29,5 +29,78 @@ Original source width in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.originalWidth : 0; + drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md index a081044c..1285feda 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md @@ -29,5 +29,78 @@ WebGL texture backing this source. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = source && source.texture ? 'READY' : 'WAIT'; + drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md index 0a18da9d..7cf7358c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md @@ -29,5 +29,78 @@ Ideal draw width in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.width : 0; + drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md index ba90d41e..fe925dff 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md @@ -42,5 +42,94 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let sourceA, sourceB; + +function createTransparentCanvas() { + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + const ctx = canvas.getContext('2d'); + if (!ctx) return canvas; + + ctx.clearRect(0, 0, 128, 128); + ctx.lineWidth = 10; + ctx.strokeStyle = '#ffffff'; + ctx.strokeRect(20, 20, 88, 88); + + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(64, 64, 30, 0, Math.PI * 2); + ctx.fill(); + + return canvas; +} + +t.setup(() => { + const canvas = createTransparentCanvas(); + + sourceA = t.createTexture(canvas); + sourceA.characters(' .:-=+*#%@'); + + sourceB = t.createTexture(canvas); + sourceB.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (!sourceA || !sourceB) return; + + const time = t.frameCount * 0.05; + const pulse = 0.5 + 0.5 * Math.sin(time); + sourceB.background(pulse * 255, 100, 255 - pulse * 155); + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); + drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); + drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md index 24f09532..7288eed9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md @@ -36,5 +36,89 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const ranges = [ + { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, + { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, + { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, +]; + +let rangeSources = []; + +function drawRangeSource(source, x, y, width, height) { + t.push(); + t.translate(x, y); + t.image(source, width, height); + t.pop(); +} + +t.setup(async () => { + rangeSources = await Promise.all( + ranges.map(async (range) => { + const source = await t.loadImage(IMAGE_URL); + source.brightnessRange(range.start, range.end); + source.characters(range.characters); + source.charColorMode('fixed'); + source.charColor(range.charColor); + source.cellColorMode('fixed'); + source.cellColor('#00000000'); + return source; + }) + ); +}); + +t.draw(() => { + t.background(4, 7, 18); + if (rangeSources.length === 0) return; + + const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); + const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); + const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); + const totalWidth = panelWidth * 3 + gap * 2; + const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); + const y = -1; + + for (let i = 0; i < rangeSources.length; i++) { + const x = startX + i * (panelWidth + gap); + drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); + drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); + drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); + drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md index 6a83b248..ba04be89 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md @@ -42,5 +42,68 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let red = 40; +let blue = 80; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed').charColor(255); + techSource.cellColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + red = Math.round(40 + 40 * Math.sin(time)); + blue = Math.round(80 + 40 * Math.cos(time * 0.7)); + + techSource.cellColor(red, 40, blue); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md index b5949740..68b0225a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md @@ -35,5 +35,72 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.cellColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.cellColorMode('fixed').cellColor(20, 30, 60); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md index 40de00c8..4bc3be73 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md @@ -42,5 +42,67 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let r = 150; +let g = 150; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + r = Math.round(150 + 105 * Math.sin(time)); + g = Math.round(150 + 105 * Math.cos(time * 0.7)); + + techSource.charColor(r, g, 100); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md index 4902d066..b1d455ad 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md @@ -35,5 +35,72 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.charColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.charColorMode('fixed').charColor(140, 255, 180); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md index b010857f..c73e9d8b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md @@ -35,5 +35,68 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let pointerSource = null; + +t.setup(async () => { + pointerSource = await t.loadImage(IMAGE_URL); + pointerSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!pointerSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + pointerSource.charRotation(0); + t.image(pointerSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + pointerSource.charRotation(90); + t.image(pointerSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); + drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md index bbe45d53..0a4e222d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md @@ -35,5 +35,79 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.characters(' .oO@'); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const chars = ' .oO@'; + drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md index ea702ffa..d1728d1d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md @@ -31,5 +31,79 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); + source.clearConversions(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STACK: CLEARED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md index fd7235ae..d3326228 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md @@ -35,5 +35,56 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let source = null; + +t.setup(async () => { + source = await t.loadImage(IMAGE_URL); + source.conversionMode('brightness'); + source.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(4, 7, 18); + t.background(0); + if (!source) return; + + t.image(source, source.width, source.height); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md index bc39b77b..4e97ac69 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md @@ -35,5 +35,98 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + Object.assign(canvas, { width: 128, height: 80 }); + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 128, 80); + gradient.addColorStop(0, '#020617'); + gradient.addColorStop(0.45, '#0ea5e9'); + gradient.addColorStop(1, '#f8fafc'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 128, 80); + ctx.fillStyle = '#f97316'; + ctx.fillRect(15, 16, 34, 44); + ctx.fillStyle = '#fde68a'; + ctx.fillRect(78, 22, 34, 34); + return canvas.toDataURL(); +} + +function configureSource(source) { + source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); +} + +function brightnessPass(start, end, characters, charColor) { + return { + mode: 'brightness', + brightnessStart: start, + brightnessEnd: end, + characters, + charColorMode: 'fixed', + charColor, + }; +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([ + brightnessPass(0, 84, ' .:', '#38bdf8'), + brightnessPass(85, 169, '-=+', '#facc15'), + brightnessPass(170, 255, '*#@', '#f8fafc'), + ]); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + if (!source) return; + + const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); + const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); + const y = Math.floor(t.grid.rows * 0.12); + t.push(); + t.translate(0, y); + t.image(source, width, height); + t.pop(); + drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); + drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('PASSES: 3', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md index cf7c4c0b..e667fb5b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md @@ -27,7 +27,89 @@ Dispose of the resource and free associated WebGL textures. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.mouseClicked(() => { + if (source && !disposed) { + source.dispose(); + disposed = true; + } +}); + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = disposed ? 'Disposed' : 'Active'; + drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Overrides diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md index 8239d1e3..21a73f30 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md @@ -35,5 +35,72 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipX(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipX(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); + drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md index be33323e..469a9af1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md @@ -35,5 +35,72 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipY(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipY(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); + drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md index 206a3e4f..ce6590f4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md @@ -35,5 +35,68 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let gradientSource = null; + +t.setup(async () => { + gradientSource = await t.loadImage(IMAGE_URL); + gradientSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!gradientSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + gradientSource.invert(false); + t.image(gradientSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + gradientSource.invert(true); + t.image(gradientSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); + drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md index 90503f49..37704f58 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md @@ -29,7 +29,81 @@ Ideal draw height in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.height : 0; + drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md index 1cb74f19..f709d41d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md @@ -29,7 +29,81 @@ Original source height in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.originalHeight : 0; + drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md index 26cc46d5..3f89570c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md @@ -29,7 +29,81 @@ Original source width in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.originalWidth : 0; + drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md index f841980e..2fbf2f07 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md @@ -29,5 +29,65 @@ Source element this texture captures. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let texture = null; +let sourceCanvas = null; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + sourceCanvas = document.createElement('canvas'); + sourceCanvas.width = 120; + sourceCanvas.height = 80; + texture = t.createTexture(sourceCanvas); + texture.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(8, 10, 18); + if (!texture) return; + const ctx = sourceCanvas.getContext('2d'); + ctx.fillStyle = '#0a0d1a'; + ctx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); + ctx.fillStyle = '#38bdf8'; + ctx.beginPath(); + ctx.arc(60 + Math.sin(t.frameCount * 0.05) * 30, 40, 18, 0, Math.PI * 2); + ctx.fill(); + t.image(texture, Math.floor(t.grid.cols * 0.5), Math.floor(t.grid.rows * 0.5)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODETEXTURE.SOURCE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: BACKING ELEMENT', x, y++, 100, 220, 255); + drawText('Texture keeps its source.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const size = sourceCanvas ? sourceCanvas.width + 'x' + sourceCanvas.height : '0x0'; + drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md index 8b9abf25..0f5f77aa 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md @@ -29,7 +29,81 @@ WebGL texture backing this source. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = source && source.texture ? 'READY' : 'WAIT'; + drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md index 8a3b37b4..33087f15 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md @@ -29,7 +29,81 @@ Ideal draw width in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.width : 0; + drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md index 3e6e99ba..cdc5df2b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md @@ -42,7 +42,97 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let sourceA, sourceB; + +function createTransparentCanvas() { + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + const ctx = canvas.getContext('2d'); + if (!ctx) return canvas; + + ctx.clearRect(0, 0, 128, 128); + ctx.lineWidth = 10; + ctx.strokeStyle = '#ffffff'; + ctx.strokeRect(20, 20, 88, 88); + + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(64, 64, 30, 0, Math.PI * 2); + ctx.fill(); + + return canvas; +} + +t.setup(() => { + const canvas = createTransparentCanvas(); + + sourceA = t.createTexture(canvas); + sourceA.characters(' .:-=+*#%@'); + + sourceB = t.createTexture(canvas); + sourceB.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (!sourceA || !sourceB) return; + + const time = t.frameCount * 0.05; + const pulse = 0.5 + 0.5 * Math.sin(time); + sourceB.background(pulse * 255, 100, 255 - pulse * 155); + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); + drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); + drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md index d712254c..236508b4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md @@ -36,7 +36,92 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const ranges = [ + { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, + { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, + { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, +]; + +let rangeSources = []; + +function drawRangeSource(source, x, y, width, height) { + t.push(); + t.translate(x, y); + t.image(source, width, height); + t.pop(); +} + +t.setup(async () => { + rangeSources = await Promise.all( + ranges.map(async (range) => { + const source = await t.loadImage(IMAGE_URL); + source.brightnessRange(range.start, range.end); + source.characters(range.characters); + source.charColorMode('fixed'); + source.charColor(range.charColor); + source.cellColorMode('fixed'); + source.cellColor('#00000000'); + return source; + }) + ); +}); + +t.draw(() => { + t.background(4, 7, 18); + if (rangeSources.length === 0) return; + + const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); + const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); + const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); + const totalWidth = panelWidth * 3 + gap * 2; + const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); + const y = -1; + + for (let i = 0; i < rangeSources.length; i++) { + const x = startX + i * (panelWidth + gap); + drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); + drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); + drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); + drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md index e8c561b8..9006a260 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md @@ -42,7 +42,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let red = 40; +let blue = 80; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed').charColor(255); + techSource.cellColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + red = Math.round(40 + 40 * Math.sin(time)); + blue = Math.round(80 + 40 * Math.cos(time * 0.7)); + + techSource.cellColor(red, 40, blue); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md index e1ca7876..e78c11da 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.cellColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.cellColorMode('fixed').cellColor(20, 30, 60); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md index 71b20ee9..68f87e72 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md @@ -42,7 +42,70 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let r = 150; +let g = 150; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + r = Math.round(150 + 105 * Math.sin(time)); + g = Math.round(150 + 105 * Math.cos(time * 0.7)); + + techSource.charColor(r, g, 100); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md index 31790ac1..2baae5d8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.charColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.charColorMode('fixed').charColor(140, 255, 180); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md index a6a6024b..cf7c97f3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let pointerSource = null; + +t.setup(async () => { + pointerSource = await t.loadImage(IMAGE_URL); + pointerSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!pointerSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + pointerSource.charRotation(0); + t.image(pointerSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + pointerSource.charRotation(90); + t.image(pointerSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); + drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md index ddc50f34..f30d63b4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md @@ -35,7 +35,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.characters(' .oO@'); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const chars = ' .oO@'; + drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md index 5f1672fe..00b4ed16 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md @@ -31,7 +31,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); + source.clearConversions(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STACK: CLEARED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md index c1653157..a6d085c6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md @@ -35,7 +35,59 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let source = null; + +t.setup(async () => { + source = await t.loadImage(IMAGE_URL); + source.conversionMode('brightness'); + source.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(4, 7, 18); + t.background(0); + if (!source) return; + + t.image(source, source.width, source.height); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md index 82f6faf6..4a8cd840 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md @@ -35,7 +35,101 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + Object.assign(canvas, { width: 128, height: 80 }); + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 128, 80); + gradient.addColorStop(0, '#020617'); + gradient.addColorStop(0.45, '#0ea5e9'); + gradient.addColorStop(1, '#f8fafc'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 128, 80); + ctx.fillStyle = '#f97316'; + ctx.fillRect(15, 16, 34, 44); + ctx.fillStyle = '#fde68a'; + ctx.fillRect(78, 22, 34, 34); + return canvas.toDataURL(); +} + +function configureSource(source) { + source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); +} + +function brightnessPass(start, end, characters, charColor) { + return { + mode: 'brightness', + brightnessStart: start, + brightnessEnd: end, + characters, + charColorMode: 'fixed', + charColor, + }; +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([ + brightnessPass(0, 84, ' .:', '#38bdf8'), + brightnessPass(85, 169, '-=+', '#facc15'), + brightnessPass(170, 255, '*#@', '#f8fafc'), + ]); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + if (!source) return; + + const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); + const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); + const y = Math.floor(t.grid.rows * 0.12); + t.push(); + t.translate(0, y); + t.image(source, width, height); + t.pop(); + drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); + drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('PASSES: 3', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md index e3c4c05e..5d53a595 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md @@ -27,7 +27,89 @@ Dispose of the resource and free associated WebGL textures. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.mouseClicked(() => { + if (source && !disposed) { + source.dispose(); + disposed = true; + } +}); + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = disposed ? 'Disposed' : 'Active'; + drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); + drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md index 5c1678d4..4152fe84 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipX(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipX(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); + drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md index 3fc50469..279b6b6f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipY(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipY(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); + drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md index 234bd1fc..0b03a04b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let gradientSource = null; + +t.setup(async () => { + gradientSource = await t.loadImage(IMAGE_URL); + gradientSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!gradientSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + gradientSource.invert(false); + t.image(gradientSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + gradientSource.invert(true); + t.image(gradientSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); + drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md index 7357b9fe..b417f77c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md @@ -23,7 +23,60 @@ chainable methods. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); + video.loop(); +}); + +t.draw(() => { + t.background(6, 12, 10); + if (video) { + t.image(video); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.CREATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: VIDEO LOADING & PLAYBACK', x, y++, 100, 220, 255); + drawText('Demonstrates loadVideo API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(video ? 'STATUS: VIDEO LOADED AND PLAYING' : 'STATUS: LOADING VIDEO...', x, y++, 255, 210, 90); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Extends diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md index 0ef2a78c..534fb020 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md @@ -29,5 +29,59 @@ Current playback time in seconds. ### Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let video = null; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + video.loop(); + await video.play(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(6, 8, 20); + if (video) t.image(video, t.grid.cols - 8, t.grid.rows - 10); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.CURRENTTIME', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PLAYBACK POSITION', x, y++, 100, 220, 255); + drawText('Read current video time.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const now = video ? video.currentTime.toFixed(2) : '0.00'; + const dur = video ? video.duration.toFixed(2) : '0.00'; + drawText(`TIME: ${now}`, x, y++, 255, 210, 90); + drawText(`DUR: ${dur}`, x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md index c31de6e5..83cb5503 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md @@ -29,5 +29,91 @@ Total video duration in seconds. ### Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let dur = 0; +let pct = 0; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); + video.loop(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video, t.grid.cols - 8, t.grid.rows - 10); + + dur = video.duration || 0; + const maxExpectedDuration = 10; + pct = Math.min(dur / maxExpectedDuration, 1); + + const gaugeWidth = Math.floor(t.grid.cols * 0.5); + const startX = -Math.floor(gaugeWidth / 2); + const filled = Math.floor(pct * gaugeWidth); + + t.push(); + t.translate(startX, 3); + for (let i = 0; i < gaugeWidth; i++) { + t.push(); + t.translate(i, 0); + if (i < filled) { + t.charColor(180, 255, 180); + t.char('■'); + } else { + t.charColor(60, 70, 95); + t.char('·'); + } + t.point(); + t.pop(); + } + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.DURATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TOTAL RUNTIME DURATION', x, y++, 100, 220, 255); + drawText('Length of the loaded video.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + drawText(`DURATION: ${dur.toFixed(3)}s`, x, y++, 255, 210, 90); + const pctStr = `${(pct * 100).toFixed(0)}% of Max Reference (10.0s)`; + drawText(pctStr, x, y++, 160, 170, 195); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md index 2d9049f7..061ee55d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md @@ -29,7 +29,81 @@ Ideal draw height in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.height : 0; + drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md index 64aaa6f6..f58c2d47 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md @@ -29,5 +29,77 @@ Whether the video is currently playing. ### Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let playing = false; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); + video.loop(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video, t.grid.cols - 8, t.grid.rows - 10); + playing = video.isPlaying; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.ISPLAYING', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PLAYBACK STATE INQUIRY', x, y++, 100, 220, 255); + drawText('Checks if video is playing.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + const stateStr = playing ? '▶ ACTIVE PLAYING' : '⏸ PAUSED'; + const stateColor = playing ? [120, 255, 120] : [255, 120, 120]; + drawText(`STATE: ${stateStr}`, x, y++, ...stateColor); + drawText(`isPlaying: ${playing}`, x, y++, 255, 210, 90); + drawText('CLICK ANYWHERE TO TOGGLE PLAYBACK', x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(async () => { + if (!video) return; + if (video.isPlaying) { + video.pause(); + } else { + await video.play(); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md index 5c3800aa..2f750f2e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md @@ -29,7 +29,81 @@ Original source height in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const h = source ? source.originalHeight : 0; + drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md index 5cf5f71e..89da9300 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md @@ -29,7 +29,81 @@ Original source width in pixels. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.originalWidth : 0; + drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md index 62592191..20389f76 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md @@ -29,7 +29,68 @@ Source element this texture captures. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let texture = null; +let sourceCanvas = null; + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.setup(() => { + sourceCanvas = document.createElement('canvas'); + sourceCanvas.width = 120; + sourceCanvas.height = 80; + texture = t.createTexture(sourceCanvas); + texture.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(8, 10, 18); + if (!texture) return; + const ctx = sourceCanvas.getContext('2d'); + ctx.fillStyle = '#0a0d1a'; + ctx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); + ctx.fillStyle = '#38bdf8'; + ctx.beginPath(); + ctx.arc(60 + Math.sin(t.frameCount * 0.05) * 30, 40, 18, 0, Math.PI * 2); + ctx.fill(); + t.image(texture, Math.floor(t.grid.cols * 0.5), Math.floor(t.grid.rows * 0.5)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODETEXTURE.SOURCE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: BACKING ELEMENT', x, y++, 100, 220, 255); + drawText('Texture keeps its source.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const size = sourceCanvas ? sourceCanvas.width + 'x' + sourceCanvas.height : '0x0'; + drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md index 0265b4af..f2803796 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md @@ -29,7 +29,81 @@ WebGL texture backing this source. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const state = source && source.texture ? 'READY' : 'WAIT'; + drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md index 5d29ff6f..d8c9f8b3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md @@ -29,5 +29,75 @@ Underlying HTML video element. ### Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let readyState = 0; +let videoWidth = 0; +let videoHeight = 0; +let tagName = 'null'; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); + video.loop(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video, t.grid.cols - 8, t.grid.rows - 10); + + const el = video.videoElement; + readyState = el ? el.readyState : 0; + videoWidth = el ? el.videoWidth : 0; + videoHeight = el ? el.videoHeight : 0; + tagName = el ? el.tagName.toLowerCase() : 'null'; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.VIDEOELEMENT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ACCESS NATIVE VIDEO ELEMENT', x, y++, 100, 220, 255); + drawText('Queries DOM element properties.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + drawText(`READY STATE : ${readyState}`, x, y++, 120, 205, 255); + drawText(`SOURCE WIDTH: ${videoWidth}px`, x, y++, 220, 220, 220); + drawText(`SRC HEIGHT : ${videoHeight}px`, x, y++, 220, 220, 220); + drawText(`TAG NAME : <${tagName}>`, x, y++, 180, 255, 180); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md index 39f6e09a..9f78426f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md @@ -29,7 +29,81 @@ Ideal draw width in grid cells. ### Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const w = source ? source.width : 0; + drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md index eb471e46..213718a3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md @@ -42,7 +42,97 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let sourceA, sourceB; + +function createTransparentCanvas() { + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + const ctx = canvas.getContext('2d'); + if (!ctx) return canvas; + + ctx.clearRect(0, 0, 128, 128); + ctx.lineWidth = 10; + ctx.strokeStyle = '#ffffff'; + ctx.strokeRect(20, 20, 88, 88); + + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(64, 64, 30, 0, Math.PI * 2); + ctx.fill(); + + return canvas; +} + +t.setup(() => { + const canvas = createTransparentCanvas(); + + sourceA = t.createTexture(canvas); + sourceA.characters(' .:-=+*#%@'); + + sourceB = t.createTexture(canvas); + sourceB.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + if (!sourceA || !sourceB) return; + + const time = t.frameCount * 0.05; + const pulse = 0.5 + 0.5 * Math.sin(time); + sourceB.background(pulse * 255, 100, 255 - pulse * 155); + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); + drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); + drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md index e64476ac..3d69dbe6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md @@ -36,7 +36,92 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +const ranges = [ + { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, + { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, + { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, +]; + +let rangeSources = []; + +function drawRangeSource(source, x, y, width, height) { + t.push(); + t.translate(x, y); + t.image(source, width, height); + t.pop(); +} + +t.setup(async () => { + rangeSources = await Promise.all( + ranges.map(async (range) => { + const source = await t.loadImage(IMAGE_URL); + source.brightnessRange(range.start, range.end); + source.characters(range.characters); + source.charColorMode('fixed'); + source.charColor(range.charColor); + source.cellColorMode('fixed'); + source.cellColor('#00000000'); + return source; + }) + ); +}); + +t.draw(() => { + t.background(4, 7, 18); + if (rangeSources.length === 0) return; + + const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); + const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); + const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); + const totalWidth = panelWidth * 3 + gap * 2; + const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); + const y = -1; + + for (let i = 0; i < rangeSources.length; i++) { + const x = startX + i * (panelWidth + gap); + drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); + drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); + drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); + drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md index af49fab9..fb8ca759 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md @@ -42,7 +42,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let red = 40; +let blue = 80; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed').charColor(255); + techSource.cellColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + red = Math.round(40 + 40 * Math.sin(time)); + blue = Math.round(80 + 40 * Math.cos(time * 0.7)); + + techSource.cellColor(red, 40, blue); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md index 05684d59..413fef9c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.cellColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.cellColorMode('fixed').cellColor(20, 30, 60); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md index a7e7d3b8..86098400 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md @@ -42,7 +42,70 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let techSource = null; +let r = 150; +let g = 150; + +t.setup(async () => { + techSource = await t.loadImage(IMAGE_URL); + techSource.characters(' .:-=+*#%@'); + techSource.charColorMode('fixed'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!techSource) return; + + const time = t.frameCount * 0.04; + r = Math.round(150 + 105 * Math.sin(time)); + g = Math.round(150 + 105 * Math.cos(time * 0.7)); + + techSource.charColor(r, g, 100); + + t.push(); + t.translate(0, 0); + t.image(techSource, 24, 14); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); + drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md index 8ddb0e0f..af061db6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.charColorMode('sampled'); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.charColorMode('fixed').charColor(140, 255, 180); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md index abfe6c5b..148c4819 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let pointerSource = null; + +t.setup(async () => { + pointerSource = await t.loadImage(IMAGE_URL); + pointerSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!pointerSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + pointerSource.charRotation(0); + t.image(pointerSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + pointerSource.charRotation(90); + t.image(pointerSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); + drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md index 36360e78..eefe9d3c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md @@ -35,7 +35,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.characters(' .oO@'); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const chars = ' .oO@'; + drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md index 6b862311..5643f077 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md @@ -31,7 +31,82 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; +let disposed = false; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + canvas.width = 96; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 96, 64); + gradient.addColorStop(0, '#0ea5e9'); + gradient.addColorStop(1, '#f59e0b'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 96, 64); + ctx.fillStyle = '#020617'; + ctx.fillRect(16, 16, 64, 32); + ctx.fillStyle = '#f8fafc'; + ctx.fillRect(28, 26, 40, 12); + return canvas.toDataURL(); +} + +function configureSource(value) { + value.characters(' .:-=+*#%@'); + value.charColorMode('sampled'); + value.cellColorMode('fixed'); +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); + source.clearConversions(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(5, 8, 18); + if (!source || disposed) return; + t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); + drawText('Image source conversion API.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('STACK: CLEARED', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md index 6558e415..a953c174 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md @@ -35,7 +35,59 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let source = null; + +t.setup(async () => { + source = await t.loadImage(IMAGE_URL); + source.conversionMode('brightness'); + source.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(4, 7, 18); + t.background(0); + if (!source) return; + + t.image(source, source.width, source.height); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); + drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md index 8ee5ca0a..7b7fd366 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md @@ -35,7 +35,101 @@ This instance for chaining. ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); + +let source = null; + +function createImageUrl() { + const canvas = document.createElement('canvas'); + Object.assign(canvas, { width: 128, height: 80 }); + const ctx = canvas.getContext('2d'); + const gradient = ctx.createLinearGradient(0, 0, 128, 80); + gradient.addColorStop(0, '#020617'); + gradient.addColorStop(0.45, '#0ea5e9'); + gradient.addColorStop(1, '#f8fafc'); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 128, 80); + ctx.fillStyle = '#f97316'; + ctx.fillRect(15, 16, 34, 44); + ctx.fillStyle = '#fde68a'; + ctx.fillRect(78, 22, 34, 34); + return canvas.toDataURL(); +} + +function configureSource(source) { + source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); +} + +function brightnessPass(start, end, characters, charColor) { + return { + mode: 'brightness', + brightnessStart: start, + brightnessEnd: end, + characters, + charColorMode: 'fixed', + charColor, + }; +} + +t.setup(async () => { + source = await t.loadImage(createImageUrl()); + configureSource(source); + source.conversions([ + brightnessPass(0, 84, ' .:', '#38bdf8'), + brightnessPass(85, 169, '-=+', '#facc15'), + brightnessPass(170, 255, '*#@', '#f8fafc'), + ]); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background(4, 7, 16); + if (!source) return; + + const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); + const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); + const y = Math.floor(t.grid.rows * 0.12); + t.push(); + t.translate(0, y); + t.image(source, width, height); + t.pop(); + drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); + drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('PASSES: 3', x, y++, 140, 255, 180); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md index 31dd0543..91098829 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md @@ -27,7 +27,74 @@ Dispose the video source and release the backing media element. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let disposed = false; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(5, 7, 18); + if (video && !disposed) { + t.image(video, t.grid.cols - 8, t.grid.rows - 10); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.DISPOSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: CLEANUP AND DISPOSAL', x, y++, 100, 220, 255); + drawText('Releases video resources.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (disposed) { + drawText('STATUS: DISPOSED', x, y++, 255, 120, 120); + } else if (video) { + drawText('STATUS: ACTIVE', x, y++, 120, 255, 120); + drawText('CLICK ANYWHERE TO DISPOSE VIDEO', x, y++, 255, 210, 90); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(() => { + if (!video || disposed) return; + video.dispose(); + disposed = true; +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Overrides diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md index 557553c5..c0dae162 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipX(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipX(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); + drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md index 57eb8d36..59cb9528 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md @@ -35,7 +35,75 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let sourceA = null; +let sourceB = null; + +t.setup(async () => { + sourceA = await t.loadImage(IMAGE_URL); + sourceA.characters(' .:-=+*#%@'); + sourceA.flipY(false); + + sourceB = await t.loadImage(IMAGE_URL); + sourceB.characters(' .:-=+*#%@'); + sourceB.flipY(true); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!sourceA || !sourceB) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + t.image(sourceA, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + t.image(sourceB, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); + drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md index deeb8b69..74fd65a0 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md @@ -35,7 +35,71 @@ This instance for chaining. ## Example - +```javascript +const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 8, +}); + +const labelLayer = t.layers.add(); +let gradientSource = null; + +t.setup(async () => { + gradientSource = await t.loadImage(IMAGE_URL); + gradientSource.characters(' .:-=+*#%@'); +}); + +t.draw(() => { + t.background(6, 10, 22); + + if (!gradientSource) return; + + const imgW = 20; + const imgH = 12; + + t.push(); + t.translate(-12, 0); + gradientSource.invert(false); + t.image(gradientSource, imgW, imgH); + t.pop(); + + t.push(); + t.translate(12, 0); + gradientSource.invert(true); + t.image(gradientSource, imgW, imgH); + t.pop(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); + drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md index 0baf2416..3a07293d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md @@ -33,5 +33,73 @@ Set whether the video loops. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let currentTime = 0; +let duration = 0; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(false); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + currentTime = video.currentTime; + duration = video.duration || 1; + + if (!video.isPlaying && video.currentTime >= video.duration) { + video.time(0); + void video.play(); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.LOOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LOOP CONTROL & END EVENT', x, y++, 100, 220, 255); + drawText('Disables auto-loop, loops manually.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + drawText(`CURRENT TIME: ${currentTime.toFixed(1)}s`, x, y++, 255, 210, 90); + drawText(`DURATION : ${duration.toFixed(1)}s`, x, y++, 255, 210, 90); + drawText('LOOP MODE : MANUAL DETECT', x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md index 9afcf54a..173aef84 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md @@ -27,5 +27,76 @@ Pause video playback. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let playing = false; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + playing = video.isPlaying; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.PAUSE', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PAUSING VIDEO PLAYBACK', x, y++, 100, 220, 255); + drawText('Stops playback at current frame.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + const actionStr = playing ? 'CLICK TO PAUSE()' : 'CLICK TO RESUME WITH PLAY()'; + drawText(actionStr, x, y++, 255, 210, 90); + const state = playing ? 'PLAYING' : 'PAUSED'; + drawText(`PLAY: ${state}`, x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(async () => { + if (!video) return; + if (video.isPlaying) { + video.pause(); + } else { + await video.play(); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md index 7b84c4d5..6cf6c574 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md @@ -29,5 +29,74 @@ Promise that resolves when playback starts. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let playing = false; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.volume(0); + await video.play(); + video.pause(); + video.time(0); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + playing = video.isPlaying; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.PLAY', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: INITIATING VIDEO PLAYBACK', x, y++, 100, 220, 255); + drawText('Plays or restarts a loaded video.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + const actionStr = playing ? 'CLICK TO RESTART PLAYBACK' : 'CLICK TO CALL PLAY()'; + drawText(actionStr, x, y++, 255, 210, 90); + const state = playing ? 'PLAYING' : 'PAUSED'; + drawText(`PLAY: ${state}`, x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(async () => { + if (!video) return; + video.time(0); + await video.play(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md index c6a05041..f70d7c2a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md @@ -33,5 +33,70 @@ Set playback speed. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let rate = 1.0; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + const halfWidth = t.grid.cols / 2; + const normalizedX = (t.mouse.x + halfWidth) / t.grid.cols; + const clampedX = Math.max(0, Math.min(1, normalizedX)); + rate = 0.1 + clampedX * 3.9; + + video.speed(rate); + t.image(video); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.SPEED', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PLAYBACK RATE CONTROL', x, y++, 100, 220, 255); + drawText('Alters playback speed dynamically.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + drawText(`CURRENT SPEED: ${rate.toFixed(1)}x`, x, y++, 255, 210, 90); + drawText('MOVE MOUSE HORIZONTALLY TO CHANGE', x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md index b58517ad..d13b7818 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md @@ -27,5 +27,81 @@ Stop the video and seek to the beginning. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let playing = false; +let restartTimeout = null; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + playing = video.isPlaying; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.STOP', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: TERMINATING PLAYBACK', x, y++, 100, 220, 255); + drawText('Stops video and resets timeline.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + const state = playing ? 'PLAYING' : 'STOPPED'; + drawText(`PLAY: ${state}`, x, y++, 255, 210, 90); + drawText("PRESS 'S' TO STOP VIDEO", x, y++, 120, 205, 255); + if (restartTimeout) { + drawText('RESTARTING IN 1 SECOND...', x, y++, 140, 160, 190); + } + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.keyPressed(() => { + if (!video || !t.isKeyPressed('s')) return; + + video.stop(); + if (restartTimeout) clearTimeout(restartTimeout); + restartTimeout = setTimeout(() => { + void video.play(); + restartTimeout = null; + }, 1000); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md index 52c48839..a4e84069 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md @@ -33,5 +33,73 @@ Seek to a playback time. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let currentTime = 0; +let duration = 0; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(); + video.volume(0); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + currentTime = video.currentTime; + duration = video.duration || 1; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.TIME', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: JUMPING TO PLAYBACK TIME', x, y++, 100, 220, 255); + drawText('Sets a new playback position.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + drawText(`CURRENT TIME: ${currentTime.toFixed(1)}s`, x, y++, 255, 210, 90); + drawText(`DURATION : ${duration.toFixed(1)}s`, x, y++, 255, 210, 90); + drawText('CLICK ANYWHERE TO JUMP RANDOM TIME', x, y++, 120, 205, 255); + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(() => { + if (!video) return; + video.time(Math.random() * video.duration); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md index 8df0baf1..f15a1a41 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md @@ -33,5 +33,83 @@ Set playback volume. ## Example - +```javascript +const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, +}); + +const labelLayer = t.layers.add(); +let video = null; +let audioEnabled = false; +let level = 0; + +t.setup(async () => { + video = await t.loadVideo(VIDEO_URL); + video.characters(' .:-=+*#%@'); + video.loop(); + await video.play(); +}); + +t.draw(() => { + t.background(6, 8, 20); + if (!video) return; + + t.image(video); + + if (audioEnabled) { + const halfHeight = t.grid.rows / 2; + const normalizedY = (t.mouse.y + halfHeight) / t.grid.rows; + level = 1 - Math.max(0, Math.min(1, normalizedY)); + video.volume(level); + } +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('TEXTMODEVIDEO.VOLUME', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: AUDIO VOLUME AMPLITUDE', x, y++, 100, 220, 255); + drawText('Controls video audio loudness.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + + if (video) { + if (audioEnabled) { + drawText(`VOLUME LEVEL: ${level.toFixed(2)}`, x, y++, 255, 210, 90); + drawText('MOVE MOUSE VERTICALLY FOR VOLUME', x, y++, 120, 205, 255); + } else { + drawText('CLICK ANYWHERE TO UNMUTE AUDIO', x, y++, 255, 120, 120); + } + } else { + drawText('LOADING VIDEO...', x, y++, 255, 180, 120); + } +}); + +t.mouseClicked(async () => { + if (!video || audioEnabled) return; + + video.videoElement.muted = false; + audioEnabled = true; + await video.play(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md index 36455f1e..4cd0a238 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md @@ -50,7 +50,96 @@ Called when the plugin is installed on a [Textmodifier](../../../classes/Textmod #### Example - +```javascript +let isInstalled = false; +let coreEnergy = 0; + +const quantumPlugin = { + name: 'quantum-core', + install(textmodifier) { + isInstalled = true; + coreEnergy = 1.0; + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [quantumPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 22); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const angle = Math.atan2(y, x); + const spiral = Math.sin(dist * 0.3 - angle * 3 + tm * 2); + const norm = (spiral + 1) * 0.5; + + const charKey = dist < 3 ? '@' : dist < 8 ? '#' : norm > 0.6 ? '*' : norm > 0.3 ? '+' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + isInstalled ? Math.floor(100 + norm * 155) : 80, + isInstalled ? Math.floor(180 + norm * 75) : 80, + isInstalled ? Math.floor(255 - dist * 8) : 80 + ); + t.cellColor( + isInstalled ? Math.floor(8 + norm * 16) : 4, + isInstalled ? Math.floor(14 + norm * 20) : 4, + isInstalled ? Math.floor(32 + norm * 24) : 8 + ); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('PLUGINS.TEXTMODEPLUGIN.INSTALL', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: NEURAL MATRIX CORE IGNITION', x, y++); + t.charColor(140, 160, 190); + t.print('install(t, context) initializes state', x, y++); + t.print('during textmode instance creation.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`PLUGIN INSTALLED: ${isInstalled}`, x, y++); + t.print(`CORE ENERGY: ${(coreEnergy * 100).toFixed(0)}%`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + *** @@ -75,5 +164,62 @@ Called when the plugin is uninstalled from a [Textmodifier](../../../classes/Tex #### Example - +```javascript +let uninstalled = false; + +const myPlugin = { + name: 'uninstall-plugin', + install(textmodifier, context) {}, + uninstall(textmodifier, context) { + uninstalled = true; + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [myPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 20); +}); + +t.mouseClicked(() => { + if (uninstalled) return; + t.destroy(); + document.body.innerHTML = + '
plugin.uninstall() executed successfully.
'; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.UNINSTALL', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: PLUGIN CLEANUP HOOK', x, y++, 100, 220, 255); + drawText('Executes when the sketch is destroyed.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(uninstalled ? 'Status: Cleaned Up' : 'Status: Active (Click to uninstall)', x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md index 843f77b4..58bcd0bf 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md @@ -35,5 +35,75 @@ A function to unregister the hook. ## Example - +```javascript +let disposedCount = 0; +let layerToDispose = null; + +const hookPlugin = { + name: 'layer-disposed-hook-plugin', + install(textmodifier, context) { + context.registerLayerDisposedHook(() => { + disposedCount += 1; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [hookPlugin], +}); + +const labelLayer = t.layers.add(); + +t.setup(() => { + layerToDispose = t.layers.add({ fontSize: 16 }); +}); + +t.draw(() => { + t.background(6, 8, 20); +}); + +t.mouseClicked(() => { + if (!layerToDispose) return; + layerToDispose.dispose(); + layerToDispose = null; +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.REGISTERLAYERDISPOSEDHOOK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LAYER DISPOSED HOOK', x, y++, 100, 220, 255); + drawText('Runs when a layer is disposed.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`DISPOSED COUNT : ${disposedCount}`, x, y++, 140, 190, 255); + drawText( + layerToDispose ? 'Click to dispose layer.' : 'Layer has been disposed successfully.', + x, + y++, + 180, + 255, + 180 + ); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md index 7471109c..da096449 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md @@ -36,5 +36,56 @@ A function to unregister the hook. ## Example - +```javascript +let postRenderCount = 0; + +const hookPlugin = { + name: 'layer-post-render-hook-plugin', + install(textmodifier, context) { + context.registerLayerPostRenderHook(() => { + postRenderCount += 1; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [hookPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 20); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.REGISTERLAYERPOSTRENDERHOOK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LAYER POST-RENDER HOOK', x, y++, 100, 220, 255); + drawText('Runs after drawing framebuffers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INVOCATIONS : ${postRenderCount}`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md index dd561297..5b23d848 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md @@ -37,5 +37,56 @@ A function to unregister the hook. ## Example - +```javascript +let preRenderCount = 0; + +const hookPlugin = { + name: 'layer-pre-render-hook-plugin', + install(textmodifier, context) { + context.registerLayerPreRenderHook(() => { + preRenderCount += 1; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [hookPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 20); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.REGISTERLAYERPRERENDERHOOK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: LAYER PRE-RENDER HOOK', x, y++, 100, 220, 255); + drawText('Runs before drawing framebuffers.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INVOCATIONS : ${preRenderCount}`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md index 3170b8bd..4f43f9d5 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md @@ -36,5 +36,84 @@ A function to unregister the hook. ## Example - +```javascript +let postDrawFrame = 0; + +const vignettePlugin = { + name: 'vignette-post', + install(textmodifier, context) { + context.registerPostDrawHook(() => { + postDrawFrame++; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [vignettePlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 10, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const dist = Math.hypot(x, y); + const angle = Math.atan2(y, x); + const pattern = Math.sin(dist * 0.3 - tm * 2) * Math.cos(angle * 6); + const norm = (pattern + 1) * 0.5; + + const charKey = norm > 0.7 ? '@' : norm > 0.4 ? '*' : norm > 0.2 ? '+' : '.'; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(80 + norm * 175), Math.floor(180 + norm * 75), Math.floor(255 - norm * 100)); + t.cellColor(Math.floor(6 + norm * 12), Math.floor(12 + norm * 14), Math.floor(28 + norm * 18)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('PLUGINS.REGISTERPOSTDRAWHOOK', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: FRAME-END VIGNETTE OVERLAY', x, y++); + t.charColor(140, 160, 190); + t.print('Executes at the very end of the', x, y++); + t.print('global t.draw() frame render.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`POST-DRAW FRAMES: ${postDrawFrame}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md index 35c3ab90..940848c2 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md @@ -38,5 +38,56 @@ A function to unregister the hook. ## Example - +```javascript +let postSetupCounter = 0; + +const hookPlugin = { + name: 'post-setup-hook-plugin', + install(textmodifier, context) { + context.registerPostSetupHook(() => { + postSetupCounter += 1; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [hookPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(6, 8, 20); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.REGISTERPOSTSETUPHOOK', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: POST-SETUP LIFECYCLE HOOK', x, y++, 100, 220, 255); + drawText('Runs immediately after user setup.', x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText(`INVOCATIONS : ${postSetupCounter}`, x, y++, 140, 190, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md index 2e4967a2..7562df34 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md @@ -36,5 +36,86 @@ A function to unregister the hook. ## Example - +```javascript +let preDrawFrames = 0; +let fluidTime = 0; + +const plasmaPlugin = { + name: 'plasma-pre', + install(textmodifier, context) { + context.registerPreDrawHook(() => { + preDrawFrames++; + fluidTime += 0.06; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [plasmaPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(10, 4, 20); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + + for (let y = top; y <= bottom; y++) { + for (let x = left; x <= right; x++) { + const v1 = Math.sin(x * 0.15 + fluidTime); + const v2 = Math.sin(y * 0.15 + fluidTime * 1.3); + const v3 = Math.sin((x + y) * 0.15 + fluidTime * 0.8); + const norm = (v1 + v2 + v3 + 3) / 6; + + const charKey = norm > 0.75 ? '@' : norm > 0.5 ? '#' : norm > 0.3 ? '+' : '.'; + + t.push(); + t.translate(x, y); + t.charColor(Math.floor(180 + norm * 75), Math.floor(60 + norm * 140), Math.floor(220 - norm * 100)); + t.cellColor(Math.floor(16 + norm * 14), Math.floor(6 + norm * 10), Math.floor(24 + norm * 18)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('PLUGINS.REGISTERPREDRAWHOOK', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: GRAVITATIONAL PLASMA VORTEX', x, y++); + t.charColor(140, 160, 190); + t.print('Executes right before main t.draw()', x, y++); + t.print('runs each animation frame.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`PRE-DRAW FRAMES: ${preDrawFrames}`, x, y++); + t.print(`FLUID TIME: ${fluidTime.toFixed(2)} S`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md index 97fea677..40188af3 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md @@ -38,5 +38,89 @@ A function to unregister the hook. ## Example - +```javascript +let preSetupTriggered = false; +let matrixSeed = 0; + +const matrixPlugin = { + name: 'matrix-presetup', + install(textmodifier, context) { + context.registerPreSetupHook(() => { + preSetupTriggered = true; + matrixSeed = 1337; + }); + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [matrixPlugin], +}); + +const labelLayer = t.layers.add(); + +t.draw(() => { + t.background(4, 16, 8); + const cols = t.grid.cols; + const rows = t.grid.rows; + const left = -Math.floor((cols - 1) / 2); + const right = left + cols - 1; + const top = -Math.floor(rows / 2); + const bottom = top + rows - 1; + const tm = t.frameCount * 0.05; + + for (let x = left; x <= right; x++) { + const dropY = Math.floor((x * 17.3 + tm * 15 + matrixSeed * 0.1) % rows) + top; + for (let y = top; y <= bottom; y++) { + const dist = Math.abs(y - dropY); + const norm = Math.max(0, 1 - dist / 12); + const charKey = dist === 0 ? '@' : norm > 0.6 ? '#' : norm > 0.3 ? '|' : '.'; + + t.push(); + t.translate(x, y); + t.charColor( + dist === 0 ? 255 : Math.floor(40 + norm * 140), + dist === 0 ? 255 : Math.floor(180 + norm * 75), + dist === 0 ? 200 : Math.floor(60 + norm * 80) + ); + t.cellColor(Math.floor(4 + norm * 8), Math.floor(12 + norm * 20), Math.floor(6 + norm * 10)); + t.char(charKey); + t.point(); + t.pop(); + } + } +}); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + t.push(); + t.printAlign('left', 'top'); + t.charColor(120, 240, 180); + t.print('PLUGINS.REGISTERPRESETUPHOOK', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 210, 255); + t.print('CONCEPT: PRE-SETUP MATRIX PALETTE', x, y++); + t.charColor(140, 160, 190); + t.print('Runs immediately before t.setup()', x, y++); + t.print('executes to seed initial state.', x, y++); + t.charColor(70, 100, 140); + t.print('------------------------------------', x, y++); + t.charColor(140, 255, 200); + t.print(`PRE-SETUP RAN: ${preSetupTriggered}`, x, y++); + t.print(`MATRIX SEED: ${matrixSeed}`, x, y++); + t.pop(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md index 0af20ff0..48f745be 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md @@ -33,5 +33,89 @@ Remove a method extension from TextmodeLayer. ## Example - +```javascript +let removePulse = null; +let extensionRemoved = false; + +const extensionPlugin = { + name: 'extension-plugin', + install(_textmodifier, context) { + context.extendLayer('pulse', function (amount = 1) { + this.setPluginState('pulse', { amount }); + }); + + removePulse = () => { + context.removeLayerExtension('pulse'); + extensionRemoved = true; + }; + }, +}; + +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [extensionPlugin], +}); + +const layer = t.layers.add({ fontSize: 16 }); +const labelLayer = t.layers.add(); + +t.setup(() => { + layer.pulse(0.6); +}); + +t.draw(() => { + t.background(5, 7, 18); +}); + +layer.draw(() => { + t.clear(); + const state = layer.getPluginState('pulse'); + const amount = state?.amount ?? 0; + + t.push(); + t.char('#'); + t.rotateZ(t.frameCount * (1 + amount)); + t.charColor(255, 180, 120); + t.rect(14, 8); + t.pop(); +}); + +t.mouseClicked(() => { + if (!removePulse || extensionRemoved) { + return; + } + removePulse(); +}); + +function drawText(text, x, y, r = 220, g = 230, b = 255) { + t.push(); + t.printAlign('left', 'top'); + t.charColor(r, g, b); + t.print(text, x, y); + t.pop(); +} + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + let y = top + 3; + const x = left + 3; + + drawText('PLUGINS.REMOVELAYEREXTENSION', x, y++, 100, 255, 140); + drawText('------------------------------------', x, y++, 80, 100, 150); + drawText('CONCEPT: REMOVE LAYER EXTENSIONS', x, y++, 100, 220, 255); + const statusMsg = extensionRemoved ? 'pulse() was removed.' : 'pulse() is available on layer.'; + drawText(statusMsg, x, y++, 140, 160, 190); + drawText('------------------------------------', x, y++, 80, 100, 150); + const clickMsg = extensionRemoved ? 'pulse() removed successfully.' : 'Click to remove pulse() extension.'; + drawText(clickMsg, x, y++, 120, 205, 255); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` From 5179f53044a2865d24b2db7439d9763a1b5de694 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 00:33:42 +0200 Subject: [PATCH 02/43] chore: regenerate API docs --- .../interfaces/TextmodeExportAPI.md | 2 +- .../classes/TextmodeCamera/accessors/eyeX.md | 77 +- .../classes/TextmodeCamera/accessors/eyeY.md | 73 +- .../classes/TextmodeCamera/accessors/eyeZ.md | 73 +- .../TextmodeCamera/accessors/targetX.md | 74 +- .../TextmodeCamera/accessors/targetY.md | 78 +- .../TextmodeCamera/accessors/targetZ.md | 84 +- .../classes/TextmodeCamera/accessors/upX.md | 75 +- .../classes/TextmodeCamera/accessors/upY.md | 82 +- .../classes/TextmodeCamera/accessors/upZ.md | 83 +- .../classes/TextmodeCamera/methods/copy.md | 97 +- .../classes/TextmodeCamera/methods/lookAt.md | 81 +- .../classes/TextmodeCamera/methods/move.md | 86 +- .../TextmodeCamera/methods/setPosition.md | 80 +- .../classes/TextmodeCamera/methods/setUp.md | 70 +- .../accessors/attachmentCount.md | 71 +- .../accessors/framebuffer.md | 70 +- .../TextmodeFramebuffer/accessors/height.md | 71 +- .../TextmodeFramebuffer/accessors/textures.md | 75 +- .../TextmodeFramebuffer/accessors/width.md | 68 +- .../TextmodeFramebuffer/methods/begin.md | 68 +- .../TextmodeFramebuffer/methods/dispose.md | 83 +- .../TextmodeFramebuffer/methods/end.md | 68 +- .../TextmodeFramebuffer/methods/readPixels.md | 93 +- .../TextmodeFramebuffer/methods/resize.md | 77 +- api/textmode.js/classes/TextmodeGlyphRamp.md | 354 +----- api/textmode.js/classes/TextmodeGrid.md | 82 +- .../TextmodeGrid/accessors/cellHeight.md | 78 +- .../TextmodeGrid/accessors/cellWidth.md | 75 +- .../classes/TextmodeGrid/accessors/cols.md | 155 +-- .../classes/TextmodeGrid/accessors/height.md | 82 +- .../classes/TextmodeGrid/accessors/offsetX.md | 74 +- .../classes/TextmodeGrid/accessors/offsetY.md | 74 +- .../classes/TextmodeGrid/accessors/rows.md | 155 +-- .../classes/TextmodeGrid/accessors/width.md | 82 +- .../classes/TextmodeGrid/methods/reset.md | 84 +- .../TextmodeGrid/methods/responsive.md | 87 +- api/textmode.js/classes/TextmodeShader.md | 172 +-- api/textmode.js/classes/TextmodeVector.md | 95 +- .../classes/TextmodeVector/methods/add.md | 189 +-- .../classes/TextmodeVector/methods/copy.md | 94 +- .../classes/TextmodeVector/methods/cross.md | 189 +-- .../classes/TextmodeVector/methods/dist.md | 189 +-- .../classes/TextmodeVector/methods/div.md | 284 +---- .../classes/TextmodeVector/methods/dot.md | 189 +-- .../classes/TextmodeVector/methods/heading.md | 94 +- .../classes/TextmodeVector/methods/limit.md | 94 +- .../classes/TextmodeVector/methods/mag.md | 94 +- .../classes/TextmodeVector/methods/magSq.md | 94 +- .../classes/TextmodeVector/methods/mult.md | 284 +---- .../TextmodeVector/methods/normalize.md | 94 +- .../classes/TextmodeVector/methods/set.md | 189 +-- .../classes/TextmodeVector/methods/setMag.md | 94 +- .../classes/TextmodeVector/methods/sub.md | 189 +-- .../classes/Textmodifier/accessors/canvas.md | 80 +- .../Textmodifier/accessors/conversions.md | 47 +- .../classes/Textmodifier/accessors/errors.md | 69 +- .../classes/Textmodifier/accessors/filters.md | 47 +- .../classes/Textmodifier/accessors/font.md | 49 +- .../Textmodifier/accessors/frameCount.md | 101 +- .../classes/Textmodifier/accessors/grid.md | 46 +- .../classes/Textmodifier/accessors/height.md | 44 +- .../Textmodifier/accessors/isDisposed.md | 48 +- .../accessors/isRenderingFrame.md | 52 +- .../classes/Textmodifier/accessors/layers.md | 54 +- .../classes/Textmodifier/accessors/loading.md | 56 +- .../classes/Textmodifier/accessors/millis.md | 211 +--- .../classes/Textmodifier/accessors/overlay.md | 88 +- .../classes/Textmodifier/accessors/secs.md | 160 +-- .../classes/Textmodifier/accessors/width.md | 44 +- .../classes/Textmodifier/methods/abs.md | 71 +- .../classes/Textmodifier/methods/acos.md | 66 +- .../Textmodifier/methods/ambientLight.md | 54 +- .../Textmodifier/methods/applyMatrix.md | 52 +- .../classes/Textmodifier/methods/arc.md | 56 +- .../classes/Textmodifier/methods/asin.md | 64 +- .../classes/Textmodifier/methods/atan.md | 64 +- .../classes/Textmodifier/methods/atan2.md | 65 +- .../Textmodifier/methods/background.md | 198 +-- .../Textmodifier/methods/beginShape.md | 63 +- .../Textmodifier/methods/bezierCurve.md | 56 +- .../classes/Textmodifier/methods/box.md | 58 +- .../classes/Textmodifier/methods/camera.md | 55 +- .../classes/Textmodifier/methods/ceil.md | 60 +- .../classes/Textmodifier/methods/cellColor.md | 196 +-- .../classes/Textmodifier/methods/char.md | 96 +- .../classes/Textmodifier/methods/charColor.md | 198 +-- .../Textmodifier/methods/charRotation.md | 53 +- .../classes/Textmodifier/methods/clamp.md | 93 +- .../classes/Textmodifier/methods/clear.md | 57 +- .../classes/Textmodifier/methods/color.md | 154 +-- .../classes/Textmodifier/methods/colorMode.md | 293 +---- .../classes/Textmodifier/methods/cone.md | 58 +- .../classes/Textmodifier/methods/constrain.md | 91 +- .../classes/Textmodifier/methods/cos.md | 64 +- .../Textmodifier/methods/createCamera.md | 59 +- .../methods/createFilterShader.md | 77 +- .../Textmodifier/methods/createFramebuffer.md | 51 +- .../Textmodifier/methods/createGlyphRamp.md | 58 +- .../methods/createMaterialShader.md | 77 +- .../Textmodifier/methods/createShader.md | 66 +- .../Textmodifier/methods/createTexture.md | 56 +- .../Textmodifier/methods/createVector.md | 94 +- .../classes/Textmodifier/methods/cursor.md | 98 +- .../classes/Textmodifier/methods/cylinder.md | 58 +- .../classes/Textmodifier/methods/degrees.md | 79 +- .../classes/Textmodifier/methods/deltaTime.md | 56 +- .../classes/Textmodifier/methods/destroy.md | 51 +- .../classes/Textmodifier/methods/dist.md | 75 +- .../Textmodifier/methods/doubleClicked.md | 72 +- .../classes/Textmodifier/methods/doubleTap.md | 73 +- .../classes/Textmodifier/methods/draw.md | 50 +- .../classes/Textmodifier/methods/ease.md | 79 +- .../classes/Textmodifier/methods/ellipse.md | 55 +- .../classes/Textmodifier/methods/ellipsoid.md | 58 +- .../classes/Textmodifier/methods/endShape.md | 63 +- .../Textmodifier/methods/exitPointerLock.md | 94 +- .../classes/Textmodifier/methods/exp.md | 65 +- .../classes/Textmodifier/methods/fill.md | 195 +-- .../classes/Textmodifier/methods/filter.md | 91 +- .../classes/Textmodifier/methods/flipX.md | 57 +- .../classes/Textmodifier/methods/flipY.md | 57 +- .../classes/Textmodifier/methods/floor.md | 65 +- .../classes/Textmodifier/methods/fontSize.md | 48 +- .../classes/Textmodifier/methods/fract.md | 61 +- .../classes/Textmodifier/methods/frameRate.md | 57 +- .../classes/Textmodifier/methods/gamepad.md | 53 +- .../methods/gamepadAxisChanged.md | 58 +- .../methods/gamepadButtonPressed.md | 57 +- .../methods/gamepadButtonReleased.md | 57 +- .../Textmodifier/methods/gamepadConnected.md | 57 +- .../methods/gamepadDisconnected.md | 57 +- .../classes/Textmodifier/methods/image.md | 52 +- .../classes/Textmodifier/methods/inputGrid.md | 67 +- .../classes/Textmodifier/methods/invert.md | 61 +- .../Textmodifier/methods/isKeyPressed.md | 98 +- .../classes/Textmodifier/methods/isLooping.md | 56 +- .../Textmodifier/methods/keyPressed.md | 96 +- .../Textmodifier/methods/keyReleased.md | 95 +- .../classes/Textmodifier/methods/keyTyped.md | 90 +- .../classes/Textmodifier/methods/lerp.md | 81 +- .../Textmodifier/methods/lightFalloff.md | 53 +- .../classes/Textmodifier/methods/line.md | 57 +- .../Textmodifier/methods/lineWeight.md | 53 +- .../classes/Textmodifier/methods/loadFont.md | 86 +- .../classes/Textmodifier/methods/loadImage.md | 49 +- .../Textmodifier/methods/loadTileset.md | 62 +- .../classes/Textmodifier/methods/loadVideo.md | 49 +- .../classes/Textmodifier/methods/log.md | 65 +- .../classes/Textmodifier/methods/longPress.md | 73 +- .../classes/Textmodifier/methods/lookAt.md | 59 +- .../classes/Textmodifier/methods/loop.md | 49 +- .../classes/Textmodifier/methods/map.md | 66 +- .../classes/Textmodifier/methods/max.md | 125 +- .../classes/Textmodifier/methods/min.md | 125 +- .../Textmodifier/methods/mouseClicked.md | 84 +- .../Textmodifier/methods/mouseDragged.md | 91 +- .../Textmodifier/methods/mouseMoved.md | 87 +- .../Textmodifier/methods/mousePressed.md | 86 +- .../Textmodifier/methods/mouseReleased.md | 98 +- .../Textmodifier/methods/mouseScrolled.md | 86 +- .../classes/Textmodifier/methods/noLights.md | 53 +- .../classes/Textmodifier/methods/noLoop.md | 59 +- .../classes/Textmodifier/methods/noTexture.md | 88 +- .../classes/Textmodifier/methods/noise.md | 58 +- .../Textmodifier/methods/noiseDetail.md | 61 +- .../classes/Textmodifier/methods/noiseSeed.md | 60 +- .../classes/Textmodifier/methods/norm.md | 64 +- .../classes/Textmodifier/methods/ortho.md | 52 +- .../Textmodifier/methods/perspective.md | 54 +- .../classes/Textmodifier/methods/pinch.md | 57 +- .../Textmodifier/methods/pixelDensity.md | 169 +-- .../classes/Textmodifier/methods/point.md | 52 +- .../Textmodifier/methods/pointLight.md | 54 +- .../classes/Textmodifier/methods/pop.md | 52 +- .../classes/Textmodifier/methods/pow.md | 61 +- .../classes/Textmodifier/methods/print.md | 69 +- .../Textmodifier/methods/printAlign.md | 96 +- .../classes/Textmodifier/methods/push.md | 54 +- .../classes/Textmodifier/methods/radians.md | 73 +- .../classes/Textmodifier/methods/random.md | 239 +--- .../Textmodifier/methods/randomGaussian.md | 80 +- .../Textmodifier/methods/randomSeed.md | 66 +- .../Textmodifier/methods/randomStream.md | 59 +- .../classes/Textmodifier/methods/rect.md | 56 +- .../classes/Textmodifier/methods/redraw.md | 76 +- .../methods/requestPointerLock.md | 94 +- .../Textmodifier/methods/resetCamera.md | 53 +- .../Textmodifier/methods/resetMatrix.md | 54 +- .../Textmodifier/methods/resetShader.md | 69 +- .../Textmodifier/methods/resizeCanvas.md | 51 +- .../classes/Textmodifier/methods/rotate.md | 73 +- .../Textmodifier/methods/rotateGesture.md | 61 +- .../classes/Textmodifier/methods/rotateX.md | 55 +- .../classes/Textmodifier/methods/rotateY.md | 55 +- .../classes/Textmodifier/methods/rotateZ.md | 55 +- .../classes/Textmodifier/methods/round.md | 66 +- .../classes/Textmodifier/methods/scale.md | 73 +- .../classes/Textmodifier/methods/setCamera.md | 66 +- .../Textmodifier/methods/setUniform.md | 71 +- .../Textmodifier/methods/setUniforms.md | 70 +- .../classes/Textmodifier/methods/setup.md | 56 +- .../classes/Textmodifier/methods/shader.md | 72 +- .../classes/Textmodifier/methods/sin.md | 69 +- .../classes/Textmodifier/methods/sphere.md | 58 +- .../classes/Textmodifier/methods/sq.md | 64 +- .../classes/Textmodifier/methods/sqrt.md | 66 +- .../classes/Textmodifier/methods/stroke.md | 195 +-- .../classes/Textmodifier/methods/swipe.md | 81 +- .../classes/Textmodifier/methods/tan.md | 66 +- .../classes/Textmodifier/methods/tap.md | 73 +- .../Textmodifier/methods/targetFrameRate.md | 53 +- .../classes/Textmodifier/methods/texture.md | 76 +- .../classes/Textmodifier/methods/torus.md | 58 +- .../Textmodifier/methods/touchCancelled.md | 73 +- .../Textmodifier/methods/touchEnded.md | 73 +- .../Textmodifier/methods/touchMoved.md | 73 +- .../Textmodifier/methods/touchStarted.md | 73 +- .../classes/Textmodifier/methods/translate.md | 55 +- .../Textmodifier/methods/translateX.md | 156 +-- .../Textmodifier/methods/translateY.md | 145 +-- .../Textmodifier/methods/translateZ.md | 124 +- .../classes/Textmodifier/methods/triangle.md | 50 +- .../Textmodifier/methods/useTileColors.md | 48 +- .../classes/Textmodifier/methods/vertex.md | 90 +- .../Textmodifier/methods/windowResized.md | 50 +- .../Textmodifier/properties/BLEND_ADDITIVE.md | 77 +- .../properties/BLEND_COLOR_BURN.md | 77 +- .../properties/BLEND_COLOR_DODGE.md | 77 +- .../Textmodifier/properties/BLEND_DARKEN.md | 77 +- .../properties/BLEND_DIFFERENCE.md | 77 +- .../properties/BLEND_EXCLUSION.md | 77 +- .../properties/BLEND_HARD_LIGHT.md | 77 +- .../Textmodifier/properties/BLEND_LIGHTEN.md | 77 +- .../Textmodifier/properties/BLEND_MULTIPLY.md | 77 +- .../Textmodifier/properties/BLEND_NORMAL.md | 78 +- .../Textmodifier/properties/BLEND_OVERLAY.md | 77 +- .../Textmodifier/properties/BLEND_SCREEN.md | 77 +- .../properties/BLEND_SOFT_LIGHT.md | 77 +- .../Textmodifier/properties/BLEND_SUBTRACT.md | 77 +- .../classes/Textmodifier/properties/LINES.md | 56 +- .../Textmodifier/properties/LINE_LOOP.md | 55 +- .../Textmodifier/properties/LINE_STRIP.md | 55 +- .../classes/Textmodifier/properties/POINTS.md | 54 +- .../classes/Textmodifier/properties/QUADS.md | 60 +- .../Textmodifier/properties/QUAD_STRIP.md | 57 +- .../Textmodifier/properties/TRIANGLES.md | 58 +- .../Textmodifier/properties/TRIANGLE_FAN.md | 59 +- .../Textmodifier/properties/TRIANGLE_STRIP.md | 56 +- .../Textmodifier/properties/displayHeight.md | 74 +- .../Textmodifier/properties/displayWidth.md | 74 +- .../Textmodifier/properties/gamepads.md | 51 +- .../Textmodifier/properties/lastKeyPressed.md | 84 +- .../properties/lastKeyReleased.md | 86 +- .../Textmodifier/properties/modifierState.md | 54 +- .../classes/Textmodifier/properties/mouse.md | 62 +- .../Textmodifier/properties/mouseIsPressed.md | 87 +- .../classes/Textmodifier/properties/movedX.md | 94 +- .../classes/Textmodifier/properties/movedY.md | 94 +- .../classes/Textmodifier/properties/pmouse.md | 98 +- .../Textmodifier/properties/pressedKeys.md | 93 +- .../Textmodifier/properties/touches.md | 58 +- .../Textmodifier/properties/windowHeight.md | 78 +- .../Textmodifier/properties/windowWidth.md | 78 +- api/textmode.js/classes/textmode.md | 74 +- .../classes/textmode/accessors/version.md | 96 +- .../classes/textmode/methods/create.md | 67 +- .../classes/textmode/methods/setErrorLevel.md | 98 +- .../enumerations/ShapeAssemblyMode.md | 510 +------- .../namespaces/color/classes/TextmodeColor.md | 87 +- .../TextmodeColor/accessors/normalized.md | 75 +- .../classes/TextmodeColor/accessors/rgb.md | 86 +- .../classes/TextmodeColor/accessors/rgba.md | 98 +- .../TextmodeColor/methods/withAlpha.md | 55 +- .../classes/TextmodeColor/properties/a.md | 94 +- .../classes/TextmodeColor/properties/b.md | 75 +- .../classes/TextmodeColor/properties/g.md | 73 +- .../classes/TextmodeColor/properties/r.md | 78 +- .../classes/TextmodeConversionManager.md | 173 +-- .../interfaces/TextmodeConversionContext.md | 90 +- .../interfaces/TextmodeConversionStrategy.md | 173 +-- .../filters/classes/TextmodeFilterManager.md | 172 +-- .../namespaces/fonts/classes/TextmodeFont.md | 87 +- .../TextmodeFont/accessors/characterMap.md | 79 +- .../TextmodeFont/accessors/characters.md | 79 +- .../classes/TextmodeFont/accessors/font.md | 72 +- .../TextmodeFont/accessors/fontSize.md | 71 +- .../TextmodeFont/accessors/framebuffer.md | 74 +- .../accessors/maxGlyphDimensions.md | 70 +- .../TextmodeFont/accessors/textureColumns.md | 68 +- .../TextmodeFont/accessors/textureRows.md | 68 +- .../classes/TextmodeFont/methods/dispose.md | 98 +- .../fonts/classes/TextmodeTileset.md | 74 +- .../accessors/cellDimensions.md | 88 +- .../TextmodeTileset/accessors/cellHeight.md | 87 +- .../TextmodeTileset/accessors/cellWidth.md | 87 +- .../TextmodeTileset/accessors/characterMap.md | 87 +- .../TextmodeTileset/accessors/characters.md | 93 +- .../TextmodeTileset/accessors/columns.md | 88 +- .../accessors/fontFramebuffer.md | 74 +- .../TextmodeTileset/accessors/fontSize.md | 90 +- .../TextmodeTileset/accessors/framebuffer.md | 93 +- .../accessors/maxGlyphDimensions.md | 87 +- .../accessors/nativeCellDimensions.md | 89 +- .../classes/TextmodeTileset/accessors/rows.md | 89 +- .../accessors/textureColumns.md | 87 +- .../TextmodeTileset/accessors/textureRows.md | 88 +- .../TextmodeTileset/methods/dispose.md | 96 +- .../accessors/asciiFramebuffer.md | 63 +- .../accessors/drawFramebuffer.md | 74 +- .../classes/TextmodeLayer/accessors/font.md | 76 +- .../classes/TextmodeLayer/accessors/grid.md | 63 +- .../classes/TextmodeLayer/accessors/height.md | 56 +- .../TextmodeLayer/accessors/texture.md | 59 +- .../classes/TextmodeLayer/accessors/width.md | 56 +- .../TextmodeLayer/methods/blendMode.md | 93 +- .../classes/TextmodeLayer/methods/camera.md | 93 +- .../TextmodeLayer/methods/createCamera.md | 97 +- .../methods/deletePluginState.md | 76 +- .../classes/TextmodeLayer/methods/draw.md | 85 +- .../classes/TextmodeLayer/methods/filter.md | 82 +- .../classes/TextmodeLayer/methods/fontSize.md | 71 +- .../TextmodeLayer/methods/getPluginState.md | 86 +- .../TextmodeLayer/methods/hasPluginState.md | 72 +- .../classes/TextmodeLayer/methods/hide.md | 99 +- .../classes/TextmodeLayer/methods/loadFont.md | 2 +- .../TextmodeLayer/methods/loadTileset.md | 93 +- .../classes/TextmodeLayer/methods/lookAt.md | 93 +- .../classes/TextmodeLayer/methods/offset.md | 79 +- .../classes/TextmodeLayer/methods/opacity.md | 86 +- .../classes/TextmodeLayer/methods/ortho.md | 85 +- .../TextmodeLayer/methods/perspective.md | 92 +- .../TextmodeLayer/methods/resetCamera.md | 94 +- .../classes/TextmodeLayer/methods/rotateZ.md | 74 +- .../TextmodeLayer/methods/setCamera.md | 97 +- .../TextmodeLayer/methods/setPluginState.md | 81 +- .../classes/TextmodeLayer/methods/show.md | 78 +- .../TextmodeLayer/methods/useTileColors.md | 97 +- .../TextmodeLayerManager/accessors/all.md | 72 +- .../TextmodeLayerManager/accessors/base.md | 92 +- .../TextmodeLayerManager/accessors/filters.md | 99 +- .../accessors/resultFramebuffer.md | 94 +- .../TextmodeLayerManager/methods/add.md | 91 +- .../TextmodeLayerManager/methods/clear.md | 99 +- .../TextmodeLayerManager/methods/move.md | 97 +- .../TextmodeLayerManager/methods/remove.md | 97 +- .../TextmodeLayerManager/methods/swap.md | 99 +- .../layering/enumerations/LayerBlendMode.md | 1079 +---------------- api/textmode.js/namespaces/layering/index.md | 6 - .../interfaces/TextmodeLayerOptions.md | 2 +- .../variables/TEXTMODE_LAYER_BLEND_MODES.md | 30 - .../namespaces/media/classes/TextmodeImage.md | 82 +- .../classes/TextmodeImage/accessors/height.md | 76 +- .../TextmodeImage/accessors/originalHeight.md | 76 +- .../TextmodeImage/accessors/originalWidth.md | 76 +- .../TextmodeImage/accessors/texture.md | 76 +- .../classes/TextmodeImage/accessors/width.md | 76 +- .../TextmodeImage/methods/background.md | 92 +- .../TextmodeImage/methods/brightnessRange.md | 87 +- .../TextmodeImage/methods/cellColor.md | 66 +- .../TextmodeImage/methods/cellColorMode.md | 70 +- .../TextmodeImage/methods/charColor.md | 65 +- .../TextmodeImage/methods/charColorMode.md | 70 +- .../TextmodeImage/methods/charRotation.md | 66 +- .../TextmodeImage/methods/characters.md | 77 +- .../TextmodeImage/methods/clearConversions.md | 77 +- .../TextmodeImage/methods/conversionMode.md | 54 +- .../TextmodeImage/methods/conversions.md | 96 +- .../classes/TextmodeImage/methods/dispose.md | 84 +- .../classes/TextmodeImage/methods/flipX.md | 70 +- .../classes/TextmodeImage/methods/flipY.md | 70 +- .../classes/TextmodeImage/methods/invert.md | 66 +- .../TextmodeSource/accessors/height.md | 75 +- .../accessors/originalHeight.md | 75 +- .../TextmodeSource/accessors/originalWidth.md | 75 +- .../TextmodeSource/accessors/texture.md | 75 +- .../classes/TextmodeSource/accessors/width.md | 75 +- .../TextmodeSource/methods/background.md | 91 +- .../TextmodeSource/methods/brightnessRange.md | 86 +- .../TextmodeSource/methods/cellColor.md | 65 +- .../TextmodeSource/methods/cellColorMode.md | 69 +- .../TextmodeSource/methods/charColor.md | 64 +- .../TextmodeSource/methods/charColorMode.md | 69 +- .../TextmodeSource/methods/charRotation.md | 65 +- .../TextmodeSource/methods/characters.md | 76 +- .../methods/clearConversions.md | 76 +- .../TextmodeSource/methods/conversionMode.md | 53 +- .../TextmodeSource/methods/conversions.md | 95 +- .../classes/TextmodeSource/methods/dispose.md | 84 +- .../classes/TextmodeSource/methods/flipX.md | 69 +- .../classes/TextmodeSource/methods/flipY.md | 69 +- .../classes/TextmodeSource/methods/invert.md | 65 +- .../TextmodeTexture/accessors/height.md | 76 +- .../accessors/originalHeight.md | 76 +- .../accessors/originalWidth.md | 76 +- .../TextmodeTexture/accessors/source.md | 62 +- .../TextmodeTexture/accessors/texture.md | 76 +- .../TextmodeTexture/accessors/width.md | 76 +- .../TextmodeTexture/methods/background.md | 92 +- .../methods/brightnessRange.md | 87 +- .../TextmodeTexture/methods/cellColor.md | 66 +- .../TextmodeTexture/methods/cellColorMode.md | 70 +- .../TextmodeTexture/methods/charColor.md | 65 +- .../TextmodeTexture/methods/charColorMode.md | 70 +- .../TextmodeTexture/methods/charRotation.md | 66 +- .../TextmodeTexture/methods/characters.md | 77 +- .../methods/clearConversions.md | 77 +- .../TextmodeTexture/methods/conversionMode.md | 54 +- .../TextmodeTexture/methods/conversions.md | 96 +- .../TextmodeTexture/methods/dispose.md | 84 +- .../classes/TextmodeTexture/methods/flipX.md | 70 +- .../classes/TextmodeTexture/methods/flipY.md | 70 +- .../classes/TextmodeTexture/methods/invert.md | 66 +- .../namespaces/media/classes/TextmodeVideo.md | 55 +- .../TextmodeVideo/accessors/currentTime.md | 56 +- .../TextmodeVideo/accessors/duration.md | 88 +- .../classes/TextmodeVideo/accessors/height.md | 76 +- .../TextmodeVideo/accessors/isPlaying.md | 74 +- .../TextmodeVideo/accessors/originalHeight.md | 76 +- .../TextmodeVideo/accessors/originalWidth.md | 76 +- .../classes/TextmodeVideo/accessors/source.md | 63 +- .../TextmodeVideo/accessors/texture.md | 76 +- .../TextmodeVideo/accessors/videoElement.md | 72 +- .../classes/TextmodeVideo/accessors/width.md | 76 +- .../TextmodeVideo/methods/background.md | 92 +- .../TextmodeVideo/methods/brightnessRange.md | 87 +- .../TextmodeVideo/methods/cellColor.md | 66 +- .../TextmodeVideo/methods/cellColorMode.md | 70 +- .../TextmodeVideo/methods/charColor.md | 65 +- .../TextmodeVideo/methods/charColorMode.md | 70 +- .../TextmodeVideo/methods/charRotation.md | 66 +- .../TextmodeVideo/methods/characters.md | 77 +- .../TextmodeVideo/methods/clearConversions.md | 77 +- .../TextmodeVideo/methods/conversionMode.md | 54 +- .../TextmodeVideo/methods/conversions.md | 96 +- .../classes/TextmodeVideo/methods/dispose.md | 69 +- .../classes/TextmodeVideo/methods/flipX.md | 70 +- .../classes/TextmodeVideo/methods/flipY.md | 70 +- .../classes/TextmodeVideo/methods/invert.md | 66 +- .../classes/TextmodeVideo/methods/loop.md | 70 +- .../classes/TextmodeVideo/methods/pause.md | 73 +- .../classes/TextmodeVideo/methods/play.md | 71 +- .../classes/TextmodeVideo/methods/speed.md | 67 +- .../classes/TextmodeVideo/methods/stop.md | 78 +- .../classes/TextmodeVideo/methods/time.md | 70 +- .../classes/TextmodeVideo/methods/volume.md | 80 +- .../plugins/interfaces/TextmodePlugin.md | 150 +-- .../methods/registerLayerDisposedHook.md | 72 +- .../methods/registerLayerPostRenderHook.md | 53 +- .../methods/registerLayerPreRenderHook.md | 53 +- .../methods/registerPostDrawHook.md | 81 +- .../methods/registerPostSetupHook.md | 53 +- .../methods/registerPreDrawHook.md | 83 +- .../methods/registerPreSetupHook.md | 86 +- .../methods/removeLayerExtension.md | 86 +- api/textmode.js/typedoc-sidebar.json | 2 +- 456 files changed, 534 insertions(+), 37529 deletions(-) delete mode 100644 api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI.md b/api/textmode.export.js/interfaces/TextmodeExportAPI.md index 4ce9a984..b229ac09 100644 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI.md +++ b/api/textmode.export.js/interfaces/TextmodeExportAPI.md @@ -19,7 +19,7 @@ Runtime export helpers that `ExportPlugin` attaches to the `Textmodifier` instan ## Example - + ## Properties diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md index 0f5b571e..1870f061 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md @@ -28,80 +28,5 @@ Current X position of the camera eye. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let eyeXVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawScene(tm, sweepX) { - t.push(); - t.ambientLight(30, 40, 70); - t.pointLight(255, 200, 150, sweepX * 0.5, 16, 20); - - for (let x = -24; x <= 24; x += 8) { - for (let z = -24; z <= 24; z += 8) { - const h = Math.floor((Math.sin(x * 0.15 + z * 0.15 + tm) * 0.5 + 0.5) * 12 + 4); - t.push(); - t.translate(x, h * 0.5, z); - t.charColor(Math.floor(80 + (x + 24) * 3.5), 180, Math.floor(240 - (z + 24) * 3.5)); - t.cellColor(10, 18, 32); - t.char('#'); - t.box(4, h, 4); - t.pop(); - } - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 24); - const tm = t.frameCount * 0.04; - const sweepX = Math.sin(tm) * 32; - - const cam = t.createCamera().setPosition(sweepX, 14, 38).lookAt(0, 4, 0); - - eyeXVal = cam.eyeX; - t.setCamera(cam); - drawScene(tm, sweepX); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.EYEX', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: LIT MONOLITH LATERAL SWEEP', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera eye X world coordinate.', x, y++); - t.print('Point light illuminates 3D monoliths.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`EYE X: ${eyeXVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md index ad6855d3..05b11a63 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md @@ -28,76 +28,5 @@ Current Y position of the camera eye. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let eyeYVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawTerrarium(tm) { - t.push(); - for (let ring = 4; ring >= 1; ring--) { - const s = ring * 6; - const h = (5 - ring) * 3; - t.push(); - t.translate(0, h * 0.5, 0); - t.charColor(Math.floor(240 - ring * 35), Math.floor(140 + ring * 25), Math.floor(80 + ring * 30)); - t.cellColor(20, 10, 16); - t.char('#'); - t.box(s, 2.5, s); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(12, 6, 18); - const tm = t.frameCount * 0.04; - const altitudeY = Math.sin(tm) * 24 + 18; - - const cam = t.createCamera().setPosition(0, altitudeY, 36).lookAt(0, 4, 0); - - eyeYVal = cam.eyeY; - t.setCamera(cam); - drawTerrarium(tm); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.EYEY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ALTITUDE OVERFLIGHT OVERVIEW', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera eye Y world coordinate.', x, y++); - t.print('Eye sweeps vertically over terrarium.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`EYE Y: ${eyeYVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md index 31cd374d..a652c74f 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md @@ -28,76 +28,5 @@ Current Z position of the camera eye. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let eyeZVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawTunnel(tm) { - t.push(); - for (let i = 0; i < 10; i++) { - const zPos = i * -12; - const s = 12 + i * 2; - t.push(); - t.translate(0, 0, zPos); - t.charColor(Math.floor(80 + i * 15), Math.floor(120 + i * 12), Math.floor(255 - i * 18)); - t.cellColor(12, 8, 24); - t.char('#'); - t.box(s, s, 2); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(10, 6, 20); - const tm = t.frameCount * 0.04; - const zoomZ = Math.cos(tm) * 40 + 50; - - const cam = t.createCamera().setPosition(0, 0, zoomZ).lookAt(0, 0, -40); - - eyeZVal = cam.eyeZ; - t.setCamera(cam); - drawTunnel(tm); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.EYEZ', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: DEPTH ZOOM TUNNEL CORRIDOR', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera eye Z world coordinate.', x, y++); - t.print('Eye zooms forward/backward on Z axis.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`EYE Z: ${eyeZVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md index cd96165f..9205ed4c 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md @@ -28,77 +28,5 @@ Current X position of the camera target. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let targetXVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawAltars(panX) { - t.push(); - t.ambientLight(25, 45, 30); - t.pointLight(120, 240, 255, panX, 12, 10); - - for (let x = -20; x <= 20; x += 10) { - t.push(); - t.translate(x, 4, 0); - t.charColor(Math.floor(100 + (x + 20) * 3.5), 240, 180); - t.cellColor(8, 24, 16); - t.char('#'); - t.box(5, 8, 5); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(4, 14, 10); - const tm = t.frameCount * 0.04; - const panX = Math.sin(tm) * 24; - - const cam = t.createCamera().setPosition(0, 12, 36).lookAt(panX, 4, 0); - - targetXVal = cam.targetX; - t.setCamera(cam); - drawAltars(panX); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.TARGETX', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: LIT 3D ALTAR PAN SCANNER', x, y++); - t.charColor(140, 160, 190); - t.print('Reads look-at target X coordinate.', x, y++); - t.print('Point light tracks target across altars.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TARGET X: ${targetXVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md index 57c9ccec..919e810d 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md @@ -28,81 +28,5 @@ Current Y position of the camera target. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let targetYVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawAttractorAltars(panY) { - t.push(); - t.ambientLight(25, 30, 45); - t.pointLight(255, 210, 60, 0, panY, 12); - - for (let i = -6; i <= 6; i++) { - const y = i * 4; - const x = Math.sin(i * 0.5) * 12; - const z = Math.cos(i * 0.5) * 8; - - t.push(); - t.translate(x, y, z); - t.charColor(Math.floor(80 + (i + 6) * 14), 255, 160); - t.cellColor(25, 10, 35); - t.char('#'); - t.box(6, 3, 6); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(12, 6, 24); - const tm = t.frameCount * 0.04; - const panY = Math.sin(tm) * 18; - - const cam = t.createCamera().setPosition(28, 4, 32).lookAt(0, panY, 0); - - targetYVal = cam.targetY; - t.setCamera(cam); - drawAttractorAltars(panY); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.TARGETY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: AIZAWA 3D ALTAR PAN SCAN', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera lookAt target Y coord.', x, y++); - t.print('Point light tracks vertical Y target.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 210, 60); - t.print(`TARGET Y: ${targetYVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md index 8200c739..3e3b3f58 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md @@ -28,87 +28,5 @@ Current Z position of the camera target. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let targetDepth = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawSubaquaticTunnel(tz) { - t.push(); - t.ambientLight(15, 30, 45); - t.pointLight(0, 220, 240, 0, 0, tz); - - for (let z = -28; z <= 28; z += 7) { - t.push(); - t.translate(0, 0, z); - const dist = Math.abs(z - tz); - const bright = Math.max(0, 1 - dist / 20); - t.charColor(Math.floor(20 + bright * 80), Math.floor(140 + bright * 115), Math.floor(180 + bright * 75)); - t.cellColor(4, 16, 28); - t.char(dist < 5 ? 'O' : 'o'); - t.ellipse(14, 10); - t.pop(); - } - - t.push(); - t.translate(0, 0, tz); - t.charColor(140, 255, 240); - t.cellColor(10, 40, 60); - t.char('*'); - t.box(4, 4, 1); - t.pop(); - t.pop(); -} - -t.draw(() => { - t.background(4, 12, 22); - const tm = t.frameCount * 0.03; - const tz = Math.sin(tm) * 20; - - const cam = t.createCamera().setPosition(18, 12, 38).lookAt(0, 0, tz); - targetDepth = cam.targetZ; - - t.setCamera(cam); - drawSubaquaticTunnel(tz); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 220); - t.print('TEXTMODECAMERA.TARGETZ', x, y++); - t.charColor(60, 90, 130); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SUBAQUATIC DEPTH SCANNER', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera look-at Z target.', x, y++); - t.print('Point light tracks focal depth ring.', x, y++); - t.charColor(60, 90, 130); - t.print('------------------------------------', x, y++); - t.charColor(120, 255, 220); - t.print(`TARGET Z: ${targetDepth.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md index bed93f89..5ca77ba8 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md @@ -28,78 +28,5 @@ Current X component of the camera up vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let upXVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawHorizon() { - t.push(); - t.char('.'); - t.charColor(60, 100, 180); - for (let x = -24; x <= 24; x += 6) { - for (let z = -24; z <= 24; z += 6) { - t.push(); - t.translate(x, 0, z); - t.charColor(x === 0 ? 255 : 80, 220, z === 0 ? 255 : 140); - t.cellColor(10, 14, 28); - t.char('+'); - t.box(4, 0.5, 4); - t.pop(); - } - } - t.pop(); -} - -t.draw(() => { - t.background(10, 10, 24); - const tm = t.frameCount * 0.04; - const rollX = Math.sin(tm); - - const cam = t.createCamera().setPosition(0, 12, 32).lookAt(0, 0, 0).setUp(rollX, 1, 0); - - upXVal = cam.upX; - t.setCamera(cam); - drawHorizon(); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.UPX', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ROLLING FLIGHT HORIZON', x, y++); - t.charColor(140, 160, 190); - t.print('Reads up-vector X component.', x, y++); - t.print('Modulating upX rolls camera view.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`UP X: ${upXVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md index 9aea8052..4908ca6a 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md @@ -28,85 +28,5 @@ Current Y component of the camera up vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ['.', ':', '=', '#', '%']; -const labelLayer = t.layers.add(); -let upVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawScene(tm) { - t.push(); - t.ambientLight(25, 35, 60); - t.pointLight(255, 200, 140, Math.sin(tm) * 20, 18, 25); - - for (let x = -24; x <= 24; x += 8) { - for (let z = -24; z <= 24; z += 8) { - const norm = Math.sin(x * 0.15 + z * 0.15 + tm) * 0.5 + 0.5; - const h = Math.floor(norm * 12 + 4); - const rIdx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); - - t.push(); - t.translate(x, h * 0.5, z); - t.charColor(Math.floor(40 + norm * 140), Math.floor(160 + norm * 80), Math.floor(220 - norm * 60)); - t.cellColor(10, 18, 36); - t.char(RAMP[rIdx]); - t.box(4, h, 4); - t.pop(); - } - } - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 24); - const tm = t.frameCount * 0.03; - const rollY = Math.sin(tm * 0.8) * 1.5; - - const cam = t.createCamera().setPosition(36, 12, 36).lookAt(0, 2, 0); - cam.setUp(0, rollY, 1); - - upVal = cam.upY; - t.setCamera(cam); - drawScene(tm); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.UPY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: GYROSCOPIC HORIZON SWEEP', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera up vector Y component.', x, y++); - t.print('Oscillating upY banks world horizon.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`UP Y VALUE: ${upVal.toFixed(3)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md index 1dcc45c2..6f6b60a7 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md @@ -28,86 +28,5 @@ Current Z component of the camera up vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let upZVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawHelixVortex(tm) { - t.push(); - t.ambientLight(30, 15, 30); - t.pointLight(255, 50, 150, 0, 0, 16); - - for (let i = -12; i <= 12; i++) { - const angle = i * 0.4 + tm * 2; - const x = Math.cos(angle) * 14; - const y = Math.sin(angle) * 14; - const z = i * 2; - - t.push(); - t.translate(x, y, z); - t.charColor(255, Math.floor(50 + (i + 12) * 8), Math.floor(150 - (i + 12) * 4)); - t.cellColor(30, 8, 25); - t.char('O'); - t.box(3, 3, 3); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(24, 6, 20); - const tm = t.frameCount * 0.04; - const tiltZ = Math.sin(tm) * 0.8; - - const cam = t - .createCamera() - .setPosition(0, 0, 42) - .lookAt(0, 0, 0) - .setUp(0, Math.cos(tm) * 0.8, tiltZ); - - upZVal = cam.upZ; - t.setCamera(cam); - drawHelixVortex(tm); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.UPZ', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HELICAL VORTEX Z-AXIS ROTOR', x, y++); - t.charColor(140, 160, 190); - t.print('Reads camera up-vector Z component.', x, y++); - t.print('Tilts camera Z-up orientation.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 50, 150); - t.print(`UP Z: ${upZVal.toFixed(2)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/methods/copy.md b/api/textmode.js/classes/TextmodeCamera/methods/copy.md index 6657d623..8872aa4b 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/copy.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/copy.md @@ -26,100 +26,5 @@ Create a copy of this camera. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let snapshotCam = null; -let useSnapshot = false; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -t.mousePressed(() => { - if (snapshotCam) { - useSnapshot = !useSnapshot; - } -}); - -function drawFortress(tm) { - t.push(); - t.ambientLight(30, 20, 40); - t.pointLight(255, 180, 100, Math.sin(tm) * 16, 14, Math.cos(tm) * 16); - - t.push(); - t.translate(0, 4, 0); - t.char('#'); - t.charColor(240, 180, 100); - t.cellColor(24, 14, 8); - t.box(10, 8, 10); - t.pop(); - - for (let i = 0; i < 4; i++) { - const a = (i * Math.PI) / 2; - t.push(); - t.translate(Math.cos(a) * 7, 7, Math.sin(a) * 7); - t.charColor(100, 220, 255); - t.cellColor(10, 20, 35); - t.char('+'); - t.box(3, 14, 3); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(14, 8, 20); - const tm = t.frameCount * 0.03; - - const liveCam = t - .createCamera() - .setPosition(Math.sin(tm) * 32, 16, Math.cos(tm) * 32) - .lookAt(0, 4, 0); - if (!snapshotCam) snapshotCam = liveCam.copy(); - - const activeCam = useSnapshot ? snapshotCam : liveCam; - t.setCamera(activeCam); - drawFortress(tm); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const modeText = useSnapshot ? 'FREEZE SNAPSHOT (CLONED)' : 'LIVE ORBIT CAMERA'; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.COPY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: DUAL-CAMERA FREEZE-FRAME', x, y++); - t.charColor(140, 160, 190); - t.print('cam.copy() creates an independent', x, y++); - t.print('deep clone of camera transformation.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`MODE: ${modeText}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO TOGGLE VIEWS', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md index 7b345008..d159e860 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md @@ -37,84 +37,5 @@ Set camera look-at target. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let bx = 0, - by = 0, - bz = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawBeaconField(bx, by, bz) { - t.push(); - for (let i = -2; i <= 2; i++) { - t.push(); - t.translate(i * 12, 6, -10); - t.charColor(80, 140, 240); - t.cellColor(8, 14, 28); - t.char('#'); - t.box(4, 12, 4); - t.pop(); - } - t.push(); - t.translate(bx, by, bz); - t.charColor(120, 255, 180); - t.cellColor(20, 40, 20); - t.char('@'); - t.box(3, 3, 3); - t.pop(); - t.pop(); -} - -t.draw(() => { - t.background(6, 12, 24); - const tm = t.frameCount * 0.04; - bx = Math.sin(tm) * 18; - by = Math.cos(tm * 0.7) * 8 + 6; - bz = Math.sin(tm * 0.5) * 12; - - const cam = t.createCamera().setPosition(0, 12, 38).lookAt(bx, by, bz); - - t.setCamera(cam); - drawBeaconField(bx, by, bz); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.LOOKAT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: TARGET LOCK TRACKING BEACON', x, y++); - t.charColor(140, 160, 190); - t.print('cam.lookAt(x, y, z) locks camera', x, y++); - t.print('view frustum onto moving target.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TARGET: [${bx.toFixed(1)}, ${by.toFixed(1)}, ${bz.toFixed(1)}]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/methods/move.md b/api/textmode.js/classes/TextmodeCamera/methods/move.md index 0a93a7fe..0373ea6e 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/move.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/move.md @@ -37,89 +37,5 @@ Move eye and target together in world space. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let totalDistance = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawHighway(camZ) { - t.push(); - t.ambientLight(20, 10, 30); - t.pointLight(255, 100, 200, 0, 10, camZ - 15); - - for (let i = 0; i < 16; i++) { - const obeliskZ = Math.floor(camZ / 12) * 12 - i * 12; - t.push(); - t.translate(-14, 4, obeliskZ); - t.charColor(255, 120, 180); - t.cellColor(28, 8, 18); - t.char('#'); - t.box(3, 8, 3); - t.pop(); - - t.push(); - t.translate(14, 4, obeliskZ); - t.charColor(100, 220, 255); - t.cellColor(8, 20, 32); - t.char('#'); - t.box(3, 8, 3); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(14, 4, 18); - - const cam = t - .createCamera() - .setPosition(0, 6, totalDistance) - .lookAt(0, 4, totalDistance - 40); - - cam.move(0, 0, -0.6); - totalDistance = cam.eyeZ; - - t.setCamera(cam); - drawHighway(totalDistance); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.MOVE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: LIT HIGHWAY OBELISK FLYBY', x, y++); - t.charColor(140, 160, 190); - t.print('cam.move(dx, dy, dz) translates eye', x, y++); - t.print('& target together in world space.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL Z DISTANCE: ${totalDistance.toFixed(1)}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md index f3dfc47f..c23f2a87 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md @@ -37,83 +37,5 @@ Set camera eye position. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let curPos = { x: 0, y: 0, z: 0 }; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawMonument(tm, eyeX, eyeY, eyeZ) { - t.push(); - t.ambientLight(60, 80, 120); - t.pointLight(255, 220, 160, eyeX, eyeY + 8, eyeZ); - t.pointLight(100, 200, 255, Math.sin(tm * 2) * 20, 24, Math.cos(tm * 2) * 20); - - for (let ring = 3; ring >= 1; ring--) { - const r = ring * 6; - t.push(); - t.translate(0, (4 - ring) * 3, 0); - t.charColor(100 + ring * 40, 200, 255 - ring * 20); - t.cellColor(12, 22, 38); - t.char('+'); - t.box(r, 2.5, r); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 24); - const tm = t.frameCount * 0.03; - - const eyeX = Math.sin(tm) * 30; - const eyeY = Math.cos(tm * 0.7) * 15 + 10; - const eyeZ = Math.cos(tm) * 30; - - curPos = { x: eyeX, y: eyeY, z: eyeZ }; - - const cam = t.createCamera().setPosition(eyeX, eyeY, eyeZ).lookAt(0, 4, 0); - - t.setCamera(cam); - drawMonument(tm, eyeX, eyeY, eyeZ); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.SETPOSITION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HARMONIC LISSAJOUS ORBIT', x, y++); - t.charColor(140, 160, 190); - t.print('cam.setPosition(x, y, z) explicitly', x, y++); - t.print('sets camera eye world coordinates.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`EYE: [${curPos.x.toFixed(1)}, ${curPos.y.toFixed(1)}, ${curPos.z.toFixed(1)}]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md index 08bf86d1..21b30cf5 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md @@ -37,73 +37,5 @@ Set camera up vector. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let upXVal = 0, - upYVal = 0; - -t.setup(() => { - t.perspective(58, 0.1, 4096); -}); - -function drawSpaceStation() { - t.push(); - t.char('#'); - t.charColor(120, 240, 255); - t.cellColor(10, 24, 40); - t.box(6, 6, 6); - t.char('+'); - t.charColor(255, 200, 100); - t.box(16, 2, 16); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 14); - const tm = t.frameCount * 0.03; - upXVal = Math.cos(tm); - upYVal = Math.sin(tm); - - const cam = t.createCamera().setPosition(0, 0, 32).lookAt(0, 0, 0).setUp(upXVal, upYVal, 0); - - t.setCamera(cam); - drawSpaceStation(); - t.resetCamera(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECAMERA.SETUP', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SPACE STATION STABILIZER', x, y++); - t.charColor(140, 160, 190); - t.print('cam.setUp(x, y, z) defines orientation', x, y++); - t.print('vector for camera up direction.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`UP VECTOR: [${upXVal.toFixed(2)}, ${upYVal.toFixed(2)}, 0.00]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md index 0453f633..a3fb7a8e 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md @@ -28,74 +28,5 @@ Number of color attachments available on this framebuffer. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - // Requesting exactly 4 color attachments - fb = t.createFramebuffer({ width: 14, height: 10, attachments: 4 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - fb.begin(); - t.clear(); - t.background(15, 12, 30); - t.charColor(255, 180, 120); - t.char('A'); - t.push(); - t.rotateZ(t.frameCount * 2.0); - t.rect(8, 6); - t.pop(); - fb.end(); - - t.push(); - t.translate(0, 3); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('ATTACHMENTCOUNT', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Number of color attachments.', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const count = fb ? fb.attachmentCount : 0; - drawText(`Attachments: ${count} color targets`, x, y++, 120, 255, 180); - drawText('0: Character/transform data', x, y++, 160, 160, 160); - drawText('1: Primary character color', x, y++, 160, 160, 160); - drawText('2: Secondary background color', x, y++, 160, 160, 160); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md index 8d80f3e5..a6c2f570 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md @@ -28,73 +28,5 @@ The underlying WebGLFramebuffer handle. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: 14, height: 14 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - fb.begin(); - t.clear(); - t.background(10, 20, 32); - t.charColor(120, 220, 255); - t.char('F'); - t.push(); - t.rotateZ(t.frameCount * 2.0); - t.rect(8, 8); - t.pop(); - fb.end(); - - t.push(); - t.translate(0, 3); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('FRAMEBUFFER', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('The raw WebGLFramebuffer handle.', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const handleExists = fb && fb.framebuffer !== null; - const typeName = fb && fb.framebuffer ? fb.framebuffer.constructor.name : 'null'; - const handle = handleExists ? 'Active' : 'null'; - drawText(`HANDLE: ${handle}`, x, y++, 120, 255, 180); - drawText(`Type : ${typeName}`, x, y++, 160, 160, 160); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md index 2b0c5209..99a91740 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md @@ -28,74 +28,5 @@ Height of the framebuffer in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: 14, height: 12 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - // Draw vertical ruler ticks inside the framebuffer showing height in cells - fb.begin(); - t.clear(); - t.background(24, 12, 18); - t.charColor(255, 100, 150); - t.char('-'); - t.rect(fb.width, fb.height); - for (let row = 0; row < fb.height; row++) { - const cx = -Math.floor(fb.width / 2); - const cy = -Math.floor(fb.height / 2) + row; - drawText(`${row}`, cx + 1, cy, 255, 220, 140); - } - fb.end(); - - t.push(); - t.translate(0, 3); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('HEIGHT', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Framebuffer height in cells (rows).', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const val = fb ? fb.height : 0; - drawText(`Framebuffer Height: ${val} cells`, x, y++, 120, 255, 180); - drawText(`Canvas : ${t.height} px`, x, y++, 160, 160, 160); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md index 2485f680..672f284e 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md @@ -28,78 +28,5 @@ The color attachment textures owned by this framebuffer. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - // 3-attachment framebuffer: char data, charColor, cellColor - fb = t.createFramebuffer({ width: 14, height: 10, attachments: 3 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - fb.begin(); - t.clear(); - t.background(10, 18, 28); - t.charColor(140, 220, 255); - t.char('T'); - t.push(); - t.rotateZ(t.frameCount * 2.0); - t.rect(8, 6); - t.pop(); - fb.end(); - - t.push(); - t.translate(0, 3); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTURES', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Array of WebGLTexture handles.', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const arr = fb ? fb.textures : []; - drawText(`Count: ${arr.length} textures`, x, y++, 120, 255, 180); - const labels = ['Char/transform', 'charColor', 'cellColor']; - for (let i = 0; i < arr.length; i++) { - const ok = arr[i] instanceof WebGLTexture; - const label = labels[i] ?? 'extra'; - const state = ok ? 'OK' : 'null'; - drawText(`[${i}] ${label}: ${state}`, x, y++, 160, 160, 160); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md index ed3dd092..d4ae9dca 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md @@ -28,71 +28,5 @@ Width of the framebuffer in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: 22, height: 10 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - fb.begin(); - t.clear(); - t.background(12, 24, 18); - - // Border - t.charColor(100, 255, 150); - t.char('|'); - t.rect(fb.width, fb.height); - - fb.end(); - - t.push(); - t.translate(0, 3); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('WIDTH', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Framebuffer width in cells (cols).', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const val = fb ? fb.width : 0; - drawText(`Framebuffer Width: ${val} cells`, x, y++, 120, 255, 180); - drawText(`Canvas : ${t.width} px`, x, y++, 160, 160, 160); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md index 26a6f12a..216a1f0c 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md @@ -29,71 +29,5 @@ and pushes renderer state so drawing commands are isolated from the previous tar ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const fb = t.createFramebuffer({ width: 20, height: 12 }); - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.05; - - fb.begin(); - t.background(15, 10, 30); - for (let i = 0; i < 12; i++) { - const angle = time + i * 0.52; - t.push(); - t.charColor(255, 150 + i * 5, 100 + i * 8); - t.char('@'); - t.translate(Math.cos(angle) * 6, Math.sin(angle) * 4); - t.rect(2, 2); - t.pop(); - } - fb.end(); - - t.background(6, 8, 18); - for (let i = 0; i < 4; i++) { - const angle = time * 0.3 + i * (Math.PI / 2); - t.push(); - t.translate(Math.cos(angle) * 16, Math.sin(angle) * 8); - t.image(fb); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('BEGIN', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Redirect draw calls to the framebuffer.', x, y++, 100, 220, 255); - drawText('4 copies orbit the screen using', x, y++, 140, 160, 190); - drawText('the same offscreen buffer.', x, y++, 140, 160, 190); - drawText('--------------------------------', x, y++, 80, 100, 150); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md index 82216737..63b88c74 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md @@ -28,88 +28,7 @@ Call this when a custom framebuffer is no longer needed to release GPU resources ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb = null; -let fbSize = 12; -let growing = true; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -function rebuildFramebuffer() { - if (fb) fb.dispose(); - - if (growing) { - fbSize += 2; - if (fbSize >= 20) growing = false; - } else { - fbSize -= 2; - if (fbSize <= 10) growing = true; - } - - fb = t.createFramebuffer({ width: fbSize, height: fbSize }); - fb.begin(); - t.background(15, 10, 30); - t.charColor(255, 100, 150); - t.char('+'); - t.rect(fbSize, fbSize); - fb.end(); -} - -t.setup(() => { - rebuildFramebuffer(); -}); - -t.draw(() => { - t.background(8, 10, 18); - - if (t.frameCount % 90 === 0) rebuildFramebuffer(); - - t.push(); - t.translate(0, 2); - t.rotateZ(t.frameCount * 1.5); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('DISPOSE', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Releases GPU resources early.', x, y++, 100, 220, 255); - drawText('Framebuffer is rebuilt every 90 frames.', x, y++, 140, 160, 190); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText(`Size: ${fbSize}x${fbSize} cells`, x, y++, 120, 255, 180); - const rem = 90 - (t.frameCount % 90); - drawText(`Rebuild in: ${rem} frames`, x, y++, 160, 160, 160); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Overrides diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md index 298cf952..9e3f8cd9 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md @@ -29,71 +29,5 @@ and viewport state from the renderer stack. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: 16, height: 10 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - // 1. Begin offscreen render pass - fb.begin(); - t.clear(); - t.background(22, 10, 30); - t.charColor(255, 180, 100); - t.char('O'); - t.rect(fb.width, fb.height); - // 2. end() restores the main canvas as the draw target - fb.end(); - - // 3. Draw the framebuffer result onto the main canvas - t.push(); - t.translate(0, 3); - t.rotateZ(t.frameCount * 1.0); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('END', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Restores main canvas target.', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('1. fb.begin() -> draw to framebuffer', x, y++, 140, 160, 190); - drawText('2. fb.end() -> restore main', x, y++, 140, 160, 190); - drawText('3. t.image(fb)-> blit to screen', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md index f880afd6..f92bd23a 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md @@ -37,96 +37,5 @@ RGBA pixel data for the selected attachment. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: 8, height: 8 }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - fb.begin(); - t.clear(); - t.background(10, 15, 30); - t.push(); - t.rotateZ(t.frameCount * 2.5); - t.charColor(255, 120, 80); - t.char('*'); - t.rect(6, 2); - t.pop(); - fb.end(); - - // Read charColor attachment and render a char-mapped pixel grid - const pixels = fb.readPixels(1); - t.push(); - t.translate(5, -1); - for (let py = 0; py < 8; py++) { - for (let px = 0; px < 8; px++) { - const idx = (py * 8 + px) * 4; - const r = pixels[idx], - g = pixels[idx + 1], - b = pixels[idx + 2]; - t.push(); - t.translate(px, py); - if (r > 30 || g > 30 || b > 30) { - t.charColor(r, g, b); - t.char('#'); - } else { - t.charColor(40, 50, 70); - t.char('.'); - } - t.point(); - t.pop(); - } - } - t.pop(); - - t.push(); - t.translate(-8, 3); - t.image(fb, 16, 16); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('READPIXELS', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Raw RGBA bytes from attachment.', x, y++, 100, 220, 255); - drawText('Right: char-map of pixel data.', x, y++, 140, 160, 190); - drawText('--------------------------------', x, y++, 80, 100, 150); - - const px = fb ? fb.readPixels(1) : []; - drawText(`Buffer: ${px.length} bytes`, x, y++, 120, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md index cdd71790..af0fb701 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md @@ -36,80 +36,5 @@ is resized to match the new dimensions. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let fb; -let currentW = 12; -let currentH = 8; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - fb = t.createFramebuffer({ width: currentW, height: currentH }); -}); - -t.draw(() => { - t.background(8, 10, 18); - - // Oscillate framebuffer dimensions to demonstrate resize() - const nextW = 10 + Math.round((Math.sin(t.frameCount * 0.03) * 0.5 + 0.5) * 16); - const nextH = 6 + Math.round((Math.cos(t.frameCount * 0.04) * 0.5 + 0.5) * 10); - - if (nextW !== currentW || nextH !== currentH) { - fb.resize(nextW, nextH); - currentW = nextW; - currentH = nextH; - } - - fb.begin(); - t.clear(); - t.background(20, 10, 35); - t.charColor(255, 200, 100); - t.char('#'); - t.rect(currentW, currentH); - const sizeStr = `${currentW}x${currentH}`; - drawText(sizeStr, -Math.floor(sizeStr.length / 2), 0, 255, 255, 255); - fb.end(); - - t.push(); - t.translate(0, 3); - t.rotateZ(Math.sin(t.frameCount * 0.02) * 5); - t.image(fb); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('RESIZE', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Resize offscreen textures live.', x, y++, 100, 220, 255); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText(`W: ${currentW} H: ${currentH} cells`, x, y++, 120, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGlyphRamp.md b/api/textmode.js/classes/TextmodeGlyphRamp.md index 4dddda72..cd980c3b 100644 --- a/api/textmode.js/classes/TextmodeGlyphRamp.md +++ b/api/textmode.js/classes/TextmodeGlyphRamp.md @@ -23,79 +23,7 @@ Use [Textmodifier.createGlyphRamp](Textmodifier/methods/createGlyphRamp.md) to c ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const ramp = t.createGlyphRamp(' .:-=+*#%@'); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.035; - - const seeds = [ - { x: Math.cos(tm) * (hw * 0.5), y: Math.sin(tm * 0.8) * (hh * 0.5) }, - { x: Math.cos(tm + 2) * (hw * 0.5), y: Math.sin(tm * 1.1 + 2) * (hh * 0.5) }, - { x: Math.cos(tm + 4) * (hw * 0.5), y: Math.sin(tm * 0.9 + 4) * (hh * 0.5) }, - ]; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - let dMin = Infinity; - for (let i = 0; i < seeds.length; i++) { - const d = Math.hypot(x - seeds[i].x, y - seeds[i].y); - if (d < dMin) dMin = d; - } - - const val = Math.min(1, dMin / (hw * 0.65)); - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(40 + val * 200), Math.floor(220 - val * 100), Math.floor(160 + val * 85)); - t.cellColor(Math.floor(6 + val * 15), Math.floor(18 + val * 20), Math.floor(24 + val * 25)); - t.char(ramp.at(val)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGLYPHRAMP.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VORONOI GLYPH RAMP MAPPING', x, y++); - t.charColor(140, 160, 190); - t.print('Creates reusable density ramps.', x, y++); - t.print('Maps Voronoi distances to glyphs.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`RAMP LENGTH: ${ramp.length} GLYPHS`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Constructors @@ -121,78 +49,7 @@ At least two grapheme clusters are required. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const ramp = t.createGlyphRamp(' .:-=+*#%@'); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.035; - - const seeds = [ - { x: Math.cos(tm) * (hw * 0.5), y: Math.sin(tm * 0.8) * (hh * 0.5) }, - { x: Math.cos(tm + 2) * (hw * 0.5), y: Math.sin(tm * 1.1 + 2) * (hh * 0.5) }, - { x: Math.cos(tm + 4) * (hw * 0.5), y: Math.sin(tm * 0.9 + 4) * (hh * 0.5) }, - ]; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - let dMin = Infinity; - for (let i = 0; i < seeds.length; i++) { - const d = Math.hypot(x - seeds[i].x, y - seeds[i].y); - if (d < dMin) dMin = d; - } - - const val = Math.min(1, dMin / (hw * 0.65)); - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(40 + val * 200), Math.floor(220 - val * 100), Math.floor(160 + val * 85)); - t.cellColor(Math.floor(6 + val * 15), Math.floor(18 + val * 20), Math.floor(24 + val * 25)); - t.char(ramp.at(val)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGLYPHRAMP.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VORONOI GLYPH RAMP MAPPING', x, y++); - t.charColor(140, 160, 190); - t.print('Creates reusable density ramps.', x, y++); - t.print('Maps Voronoi distances to glyphs.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`RAMP LENGTH: ${ramp.length} GLYPHS`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + ## Properties @@ -245,75 +102,7 @@ Character from this ramp. ##### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const ramp = t.createGlyphRamp(' .:-=+*#%@'); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(14, 8, 14); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.02; - - const n = 3 + Math.sin(tm * 0.5); - const m = 5 + Math.cos(tm * 0.5); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const nx = (x / (hw || 1)) * Math.PI; - const ny = (y / (hh || 1)) * Math.PI; - const w = Math.cos(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.cos(n * ny); - - const norm = (w + 2) / 4; - t.push(); - t.translate(x, y); - t.charColor(Math.floor(255 - norm * 160), Math.floor(100 + norm * 150), Math.floor(200 - norm * 120)); - t.cellColor(Math.floor(25 - norm * 15), Math.floor(8 + norm * 12), Math.floor(20 + norm * 10)); - t.char(ramp.at(w, -2, 2)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleW = Math.sin(t.frameCount * 0.05) * 2; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGLYPHRAMP.AT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CHLADNI CYMATIC RESONANCE', x, y++); - t.charColor(140, 160, 190); - t.print('at(v, min, max) remaps standing wave', x, y++); - t.print('nodal lines directly to the ramp.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`W: ${sampleW.toFixed(2)} -> GLYPH: "${ramp.at(sampleW, -2, 2)}"`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + #### Call Signature @@ -345,75 +134,7 @@ Character from this ramp. ##### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const ramp = t.createGlyphRamp(' .:-=+*#%@'); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(14, 8, 14); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.02; - - const n = 3 + Math.sin(tm * 0.5); - const m = 5 + Math.cos(tm * 0.5); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const nx = (x / (hw || 1)) * Math.PI; - const ny = (y / (hh || 1)) * Math.PI; - const w = Math.cos(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.cos(n * ny); - - const norm = (w + 2) / 4; - t.push(); - t.translate(x, y); - t.charColor(Math.floor(255 - norm * 160), Math.floor(100 + norm * 150), Math.floor(200 - norm * 120)); - t.cellColor(Math.floor(25 - norm * 15), Math.floor(8 + norm * 12), Math.floor(20 + norm * 10)); - t.char(ramp.at(w, -2, 2)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleW = Math.sin(t.frameCount * 0.05) * 2; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGLYPHRAMP.AT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CHLADNI CYMATIC RESONANCE', x, y++); - t.charColor(140, 160, 190); - t.print('at(v, min, max) remaps standing wave', x, y++); - t.print('nodal lines directly to the ramp.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`W: ${sampleW.toFixed(2)} -> GLYPH: "${ramp.at(sampleW, -2, 2)}"`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + *** @@ -442,70 +163,5 @@ A new shifted ramp. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const baseRamp = t.createGlyphRamp(' .:-=+*#%@'); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const angle = Math.atan2(y, x); - const dist = Math.hypot(x, y); - const shiftAmt = Math.floor((angle / (Math.PI * 2)) * baseRamp.length + tm * 3); - const shiftedRamp = baseRamp.shift(shiftAmt); - const val = (Math.sin(dist * 0.3 - tm * 2) + 1) * 0.5; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(60 + val * 180), Math.floor(200 - val * 80), Math.floor(240 - val * 60)); - t.cellColor(Math.floor(10 + val * 20), Math.floor(25 + val * 25), Math.floor(40 + val * 20)); - t.char(shiftedRamp.at(val)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const shifted = baseRamp.shift(Math.floor(t.frameCount * 0.1)); - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGLYPHRAMP.SHIFT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SHIFTED GLYPH RAMP COPY', x, y++); - t.charColor(140, 160, 190); - t.print('shift(n) returns a rotated copy.', x, y++); - t.print('Original ramp remains unchanged.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SHIFTED: "${shifted.characters}"`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid.md b/api/textmode.js/classes/TextmodeGrid.md index a6e7f155..949906d7 100644 --- a/api/textmode.js/classes/TextmodeGrid.md +++ b/api/textmode.js/classes/TextmodeGrid.md @@ -23,87 +23,7 @@ You can manually set `cols` and `rows` to lock the grid to a specific size. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 26); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.04; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const isOrigin = x === 0 && y === 0; - const isAxis = x === 0 || y === 0; - const dist = Math.hypot(x, y); - const wave = Math.sin(dist * 0.3 - tm * 2) * 0.5 + 0.5; - - let charKey = '.'; - if (isOrigin) charKey = '@'; - else if (isAxis) charKey = x === 0 ? '|' : '-'; - else charKey = wave > 0.6 ? '+' : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isOrigin ? 255 : isAxis ? 100 : Math.floor(50 + wave * 150), - isOrigin ? 220 : isAxis ? 240 : Math.floor(120 + wave * 100), - isOrigin ? 80 : isAxis ? 255 : Math.floor(180 + wave * 75) - ); - t.cellColor( - isOrigin ? 40 : isAxis ? 14 : Math.floor(6 + wave * 8), - isOrigin ? 28 : isAxis ? 20 : Math.floor(10 + wave * 12), - isOrigin ? 12 : isAxis ? 32 : Math.floor(20 + wave * 14) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const totalCells = t.grid.cols * t.grid.rows; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ARCHITECTURE MATRIX BLUEPRINT', x, y++); - t.charColor(140, 160, 190); - t.print('Grid layout determines character positioning', x, y++); - t.print('and center-based origin coordinates.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`GRID DIMENSIONS: ${t.grid.cols} X ${t.grid.rows}`, x, y++); - t.print(`TOTAL CELL COUNT: ${totalCells} CELLS`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Accessors diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md index 1c0e35ad..02007593 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md @@ -28,81 +28,5 @@ Height of each cell in screen pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.05; - const cH = t.grid.cellHeight; - - for (let y = -hh; y <= hh; y++) { - const isStride = Math.abs(y) % Math.floor(cH / 4 || 1) === 0; - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(x * 0.15 + y * (cH * 0.02) + tm); - const norm = (wave + 1) * 0.5; - - const charKey = isStride ? '=' : norm > 0.6 ? '#' : norm > 0.3 ? '+' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isStride ? 255 : Math.floor(40 + norm * 180), - isStride ? 220 : Math.floor(140 + norm * 110), - isStride ? 100 : Math.floor(240 - norm * 80) - ); - t.cellColor( - isStride ? 24 : Math.floor(6 + norm * 12), - isStride ? 16 : Math.floor(10 + norm * 14), - isStride ? 8 : Math.floor(20 + norm * 18) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const aspect = (t.grid.cellWidth / (t.grid.cellHeight || 1)).toFixed(2); - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.CELLHEIGHT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VERTICAL ASPECT STRIDE SCANNER', x, y++); - t.charColor(140, 160, 190); - t.print('Height of each cell in screen pixels.', x, y++); - t.print('Dictates vertical step stride.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`CELL HEIGHT: ${t.grid.cellHeight} PX`, x, y++); - t.print(`CELL ASPECT: ${aspect}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md index 9f60b095..b9f7e64b 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md @@ -28,78 +28,5 @@ Width of each cell in screen pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(8, 14, 24); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.05; - const cW = t.grid.cellWidth; - - for (let x = -hw; x <= hw; x++) { - const isStride = Math.abs(x) % Math.floor(cW / 3 || 1) === 0; - for (let y = -hh; y <= hh; y++) { - const wave = Math.cos(y * 0.15 + x * (cW * 0.03) + tm); - const norm = (wave + 1) * 0.5; - - const charKey = isStride ? '|' : norm > 0.6 ? '*' : norm > 0.3 ? ':' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isStride ? 100 : Math.floor(60 + norm * 180), - isStride ? 240 : Math.floor(180 + norm * 70), - isStride ? 255 : Math.floor(120 + norm * 130) - ); - t.cellColor( - isStride ? 8 : Math.floor(8 + norm * 10), - isStride ? 24 : Math.floor(12 + norm * 16), - isStride ? 32 : Math.floor(22 + norm * 14) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.CELLWIDTH', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HORIZONTAL COLUMN STRIDE MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('Width of each cell in screen pixels.', x, y++); - t.print('Dictates column horizontal density.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`CELL WIDTH: ${t.grid.cellWidth} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md index ce134e3a..bdf9e22f 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md @@ -28,82 +28,7 @@ Number of columns in the grid. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 22); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.04; - - for (let c = 0; c < cols; c++) { - const x = c - hw; - const wave = Math.sin(c * 0.3 + tm) * 0.5 + Math.cos(c * 0.12 - tm * 1.5) * 0.3 + 0.5; - const barH = Math.floor(1 + wave * (rows - 4)); - const ramp = ['.', ':', '+', '*', '#', '%', '@']; - - for (let r = 0; r < barH; r++) { - const y = hh - r; - const ci = Math.min(ramp.length - 1, Math.floor((r / Math.max(1, barH - 1)) * ramp.length)); - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(60 + wave * 140), Math.floor(140 + ci * 15), Math.floor(255 - ci * 10)); - t.cellColor(Math.floor(8 + ci * 3), Math.floor(16 + ci * 4), Math.floor(30 + ci * 5)); - t.char(ramp[ci]); - t.point(); - t.pop(); - } - - t.push(); - t.translate(x, hh - barH); - t.charColor(255, 220, 100); - t.cellColor(40, 30, 10); - t.char('*'); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.COLS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: MULTI-CHANNEL EQUALIZER SPECTRUM', x, y++); - t.charColor(140, 160, 190); - t.print('Number of columns in grid layout.', x, y++); - t.print('Renders exact 1:1 column frequency bars.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL COLUMNS: ${t.grid.cols}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Set Signature @@ -125,81 +50,5 @@ Set the number of columns and lock grid sizing until `responsive()` is called. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const presets = [16, 32, 48, 64]; -let presetIdx = 1; - -t.setup(() => { - t.grid.cols = presets[presetIdx]; -}); - -t.mousePressed(() => { - presetIdx = (presetIdx + 1) % presets.length; - t.grid.cols = presets[presetIdx]; -}); - -t.draw(() => { - t.background(6, 14, 22); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.05; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 + tm); - const norm = (wave + 1) * 0.5; - - const charKey = norm > 0.7 ? '#' : norm > 0.4 ? '+' : norm > 0.2 ? ':' : '.'; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(80 + norm * 175), Math.floor(200 + norm * 55), Math.floor(140 - norm * 60)); - t.cellColor(Math.floor(6 + norm * 10), Math.floor(18 + norm * 14), Math.floor(12 + norm * 16)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.SETCOLS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: COLUMN DENSITY QUANTIZER', x, y++); - t.charColor(140, 160, 190); - t.print('Sets column count and locks grid size', x, y++); - t.print('until responsive() is called.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`LOCKED COLS: ${t.grid.cols}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO CYCLE COLS PRESETS', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/height.md b/api/textmode.js/classes/TextmodeGrid/accessors/height.md index 13935713..79792e1d 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/height.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/height.md @@ -30,85 +30,5 @@ This is equal to `rows * cellHeight`. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 22); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let y = top; y <= bottom; y++) { - const normY = (y - top) / Math.max(1, rows - 1); - const pulse = Math.sin(normY * Math.PI * 4 - tm * 2) * 0.5 + 0.5; - - for (let x = left; x <= right; x++) { - const isBorder = x === left || x === right || y === top || y === bottom; - const isRuler = x === left + 1 || x === right - 1; - - let charKey = '.'; - if (isBorder) charKey = '#'; - else if (isRuler) charKey = (y - top) % 5 === 0 ? '+' : '|'; - else charKey = pulse > 0.6 ? '*' : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isBorder ? 255 : isRuler ? 120 : Math.floor(40 + pulse * 140), - isBorder ? 180 : isRuler ? 240 : Math.floor(100 + pulse * 100), - isBorder ? 80 : isRuler ? 200 : Math.floor(180 + pulse * 75) - ); - t.cellColor( - isBorder ? 24 : Math.floor(6 + pulse * 10), - isBorder ? 16 : Math.floor(10 + pulse * 12), - isBorder ? 8 : Math.floor(20 + pulse * 16) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.HEIGHT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VERTICAL VIEWPORT BOUNDS RULER', x, y++); - t.charColor(140, 160, 190); - t.print('Total grid height in screen pixels.', x, y++); - t.print('Equal to rows * cellHeight.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL HEIGHT: ${t.grid.height} PX`, x, y++); - t.print(`CALC: ${t.grid.rows} * ${t.grid.cellHeight} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md index 71245d36..0ee303d7 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md @@ -28,77 +28,5 @@ Horizontal offset in pixels from the canvas edge to the grid. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.04; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const isBorder = x === left || x === right || y === top || y === bottom; - const isCenter = x === 0 || y === 0; - - let charKey = '.'; - if (isBorder) charKey = '#'; - else if (isCenter) charKey = '+'; - else charKey = Math.sin(x * 0.2 + y * 0.2 + tm) > 0 ? '=' : '-'; - - t.push(); - t.translate(x, y); - t.charColor( - isBorder ? 255 : isCenter ? 120 : 80, - isBorder ? 200 : isCenter ? 240 : 160, - isBorder ? 100 : isCenter ? 180 : 240 - ); - t.cellColor(isBorder ? 30 : 10, isBorder ? 20 : 14, isBorder ? 10 : 28); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.OFFSETX', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CANVAS CENTERING ALIGNMENT', x, y++); - t.charColor(140, 160, 190); - t.print('Horizontal offset in pixels from canvas', x, y++); - t.print('edge to grid to center grid content.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`OFFSET X: ${t.grid.offsetX} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md index c17ac881..b5d8115d 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md @@ -28,77 +28,5 @@ Vertical offset in pixels from the canvas edge to the grid. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 4, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.04; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const isBorder = x === left || x === right || y === top || y === bottom; - const isCenter = x === 0 || y === 0; - - let charKey = '.'; - if (isBorder) charKey = '#'; - else if (isCenter) charKey = '+'; - else charKey = Math.cos(x * 0.2 + y * 0.2 + tm) > 0 ? '|' : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isBorder ? 255 : isCenter ? 240 : 100, - isBorder ? 180 : isCenter ? 120 : 140, - isBorder ? 120 : isCenter ? 255 : 240 - ); - t.cellColor(isBorder ? 28 : 12, isBorder ? 14 : 8, isBorder ? 12 : 30); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.OFFSETY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VERTICAL CENTERING ALIGNMENT', x, y++); - t.charColor(140, 160, 190); - t.print('Vertical offset in pixels from canvas', x, y++); - t.print('edge to grid to center grid content.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`OFFSET Y: ${t.grid.offsetY} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md index 810b48b2..df335515 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md @@ -28,82 +28,7 @@ Number of rows in the grid. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(18, 8, 6); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.04; - - for (let r = 0; r < rows; r++) { - const y = r - hh; - const wave = Math.sin(r * 0.25 + tm) * 0.5 + Math.cos(r * 0.1 - tm * 1.3) * 0.3 + 0.5; - const bandLen = Math.floor(2 + wave * (cols - 4)); - const ramp = ['.', ':', '+', '*', '#', '%', '@']; - - for (let c = 0; c < bandLen; c++) { - const x = c - hw; - const ci = Math.min(ramp.length - 1, Math.floor((c / Math.max(1, bandLen - 1)) * ramp.length)); - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(255 - ci * 15), Math.floor(120 + wave * 100), Math.floor(60 + ci * 20)); - t.cellColor(Math.floor(32 + ci * 4), Math.floor(14 + ci * 2), Math.floor(8 + ci)); - t.char(ramp[ci]); - t.point(); - t.pop(); - } - - t.push(); - t.translate(bandLen - hw, y); - t.charColor(255, 200, 100); - t.cellColor(40, 20, 8); - t.char('*'); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.ROWS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HORIZONTAL STRATIGRAPHY STRATA', x, y++); - t.charColor(140, 160, 190); - t.print('Number of rows in grid layout.', x, y++); - t.print('Renders exact 1:1 row terrain bands.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL ROWS: ${t.grid.rows}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Set Signature @@ -125,81 +50,5 @@ Set the number of rows and lock grid sizing until `responsive()` is called. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const presets = [12, 24, 36, 48]; -let presetIdx = 1; - -t.setup(() => { - t.grid.rows = presets[presetIdx]; -}); - -t.mousePressed(() => { - presetIdx = (presetIdx + 1) % presets.length; - t.grid.rows = presets[presetIdx]; -}); - -t.draw(() => { - t.background(14, 8, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.05; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.cos(x * 0.2 - tm) * Math.sin(y * 0.2 + tm); - const norm = (wave + 1) * 0.5; - - const charKey = norm > 0.7 ? '%' : norm > 0.4 ? '*' : norm > 0.2 ? '=' : '-'; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(220 + norm * 35), Math.floor(120 + norm * 100), Math.floor(80 + norm * 120)); - t.cellColor(Math.floor(20 + norm * 12), Math.floor(8 + norm * 10), Math.floor(14 + norm * 16)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.SETROWS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ROW DENSITY QUANTIZER', x, y++); - t.charColor(140, 160, 190); - t.print('Sets row count and locks grid size', x, y++); - t.print('until responsive() is called.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`LOCKED ROWS: ${t.grid.rows}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO CYCLE ROWS PRESETS', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/width.md b/api/textmode.js/classes/TextmodeGrid/accessors/width.md index 203fffc6..55320abf 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/width.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/width.md @@ -30,85 +30,5 @@ This is equal to `cols * cellWidth`. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(10, 14, 24); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let x = left; x <= right; x++) { - const normX = (x - left) / Math.max(1, cols - 1); - const pulse = Math.cos(normX * Math.PI * 4 - tm * 2) * 0.5 + 0.5; - - for (let y = top; y <= bottom; y++) { - const isBorder = x === left || x === right || y === top || y === bottom; - const isRuler = y === top + 1 || y === bottom - 1; - - let charKey = '.'; - if (isBorder) charKey = '#'; - else if (isRuler) charKey = (x - left) % 5 === 0 ? '+' : '-'; - else charKey = pulse > 0.6 ? '*' : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isBorder ? 255 : isRuler ? 100 : Math.floor(60 + pulse * 140), - isBorder ? 200 : isRuler ? 220 : Math.floor(140 + pulse * 100), - isBorder ? 100 : isRuler ? 255 : Math.floor(120 + pulse * 80) - ); - t.cellColor( - isBorder ? 24 : Math.floor(8 + pulse * 10), - isBorder ? 18 : Math.floor(14 + pulse * 12), - isBorder ? 10 : Math.floor(24 + pulse * 14) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.WIDTH', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HORIZONTAL VIEWPORT BOUNDS RULER', x, y++); - t.charColor(140, 160, 190); - t.print('Total grid width in screen pixels.', x, y++); - t.print('Equal to cols * cellWidth.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL WIDTH: ${t.grid.width} PX`, x, y++); - t.print(`CALC: ${t.grid.cols} * ${t.grid.cellWidth} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/methods/reset.md b/api/textmode.js/classes/TextmodeGrid/methods/reset.md index 80ccd8b8..669521dc 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/reset.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/reset.md @@ -32,87 +32,5 @@ You typically do not need to call this method directly. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let resetPulse = 0; - -t.setup(() => {}); - -t.mousePressed(() => { - t.grid.reset(); - resetPulse = 1.0; -}); - -t.draw(() => { - t.background(6, 12, 24); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - if (resetPulse > 0) resetPulse -= 0.03; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const wave = Math.sin(dist * 0.4 - tm * 3 + resetPulse * 6); - const norm = (wave + 1) * 0.5; - - const charKey = resetPulse > 0.5 ? '#' : norm > 0.6 ? '+' : norm > 0.3 ? ':' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - resetPulse > 0 ? 255 : Math.floor(60 + norm * 180), - resetPulse > 0 ? Math.floor(180 + resetPulse * 75) : Math.floor(140 + norm * 110), - resetPulse > 0 ? Math.floor(100 + resetPulse * 155) : Math.floor(220 - norm * 80) - ); - t.cellColor(Math.floor(8 + norm * 12), Math.floor(12 + norm * 14), Math.floor(24 + norm * 16)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.RESET', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: INTERACTIVE GRID RECALCULATION', x, y++); - t.charColor(140, 160, 190); - t.print('Recalculates columns and rows from', x, y++); - t.print('current canvas & cell dimensions.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`GRID: ${t.grid.cols} X ${t.grid.rows}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO TRIGGER RESET()', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md index 718ecc67..b79a3e39 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md @@ -28,90 +28,5 @@ A grid becomes non-responsive when either `cols` or `rows` is manually set. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let isManual = false; - -t.setup(() => {}); - -t.mousePressed(() => { - isManual = !isManual; - if (isManual) { - t.grid.cols = 32; - t.grid.rows = 16; - } else { - t.grid.responsive(); - t.grid.reset(); - } -}); - -t.draw(() => { - t.background(8, 12, 26); - const cols = t.grid.cols; - const rows = t.grid.rows; - const hw = Math.floor(cols / 2); - const hh = Math.floor(rows / 2); - const tm = t.frameCount * 0.04; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 - tm); - const norm = (wave + 1) * 0.5; - - const charKey = isManual ? (norm > 0.5 ? '#' : '=') : norm > 0.6 ? '*' : norm > 0.3 ? '+' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isManual ? 255 : Math.floor(80 + norm * 160), - isManual ? Math.floor(140 + norm * 100) : Math.floor(200 + norm * 55), - isManual ? 100 : Math.floor(140 - norm * 60) - ); - t.cellColor(isManual ? 24 : 8, isManual ? 12 : 16, isManual ? 8 : 28); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const modeText = isManual ? 'MANUAL LOCKED (32x16)' : 'AUTO RESPONSIVE'; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEGRID.RESPONSIVE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: RESPONSIVE AUTO-SIZING TOGGLE', x, y++); - t.charColor(140, 160, 190); - t.print('Restores responsive sizing so resizes', x, y++); - t.print('recalculate columns and rows.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`GRID SIZING: ${modeText}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO TOGGLE RESPONSIVE', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeShader.md b/api/textmode.js/classes/TextmodeShader.md index 6c5afd97..62a24fd8 100644 --- a/api/textmode.js/classes/TextmodeShader.md +++ b/api/textmode.js/classes/TextmodeShader.md @@ -44,79 +44,7 @@ Get the WebGL program ##### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let customShader = null; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - customShader = await t.createMaterialShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - vec2 centered = v_uv - 0.5; - float rings = sin(length(centered) * 42.0 - u_time * 3.0); - float scan = sin((v_uv.x + v_uv.y) * 26.0 + u_time * 2.0); - float glyph = step(0.0, rings + scan * 0.45); - o_character = vec4(glyph, 0.0, 0.0, 1.0); - o_primaryColor = vec4(0.28 + glyph * 0.6, 0.82, 1.0, 1.0); - o_secondaryColor = vec4(0.02, 0.04, 0.09, 1.0); -}`); -}); - -t.draw(() => { - t.background(4, 7, 18); - - if (!customShader) return; - - t.shader(customShader); - t.setUniform('u_time', t.frameCount * 0.025); - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESHADER.PROGRAM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: WEBGL PROGRAM HANDLE', x, y++, 100, 220, 255); - drawText('Filter shader draws the grid.', x, y++, 140, 160, 190); - drawText('program exposes the raw handle.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - const ready = customShader && customShader.program instanceof WebGLProgram; - const state = ready ? 'READY' : 'WAIT'; - drawText(`PROGRAM: ${state}`, x, y++, 140, 255, 180); - drawText('TYPE: WEBGLPROGRAM', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Methods @@ -134,103 +62,7 @@ Dispose of WebGL resources used by this shader. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let customShader = null; -let isDisposed = false; - -function drawText(text, x, y, r = 200, g = 220, b = 255) { - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -async function createShader() { - const vert = `#version 300 es - in vec4 a_position; in vec2 a_uv; out vec2 v_uv; - void main() { gl_Position = a_position; v_uv = a_uv; }`; - const frag = `#version 300 es - precision highp float; in vec2 v_uv; - layout(location = 0) out vec4 o_char; - layout(location = 1) out vec4 o_fg; - layout(location = 2) out vec4 o_bg; - void main() { - float s = step(0.5, fract((v_uv.x + v_uv.y) * 10.0)); - o_char = vec4(s, 0.0, 0.0, 0.0); - o_fg = vec4(1.0, 0.75 - s * 0.3, 0.25 + s * 0.4, 1.0); - o_bg = vec4(0.03, 0.05, 0.1, 1.0); - }`; - customShader = await t.createShader(vert, frag); - isDisposed = false; -} - -t.setup(async () => { - await createShader(); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (customShader && !isDisposed) { - t.push(); - t.shader(customShader); - t.charColor(255, 180, 100); - t.rect(14, 6); - t.resetShader(); - t.pop(); - } else { - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(14, 6); - t.pop(); - } -}); - -t.mouseClicked(async () => { - if (customShader && !isDisposed) { - customShader.dispose(); - isDisposed = true; - } else { - await createShader(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('DISPOSE', x, y++, 100, 255, 140); - drawText('--------------------------------', x, y++, 80, 100, 150); - drawText('Frees the GL program handle.', x, y++, 100, 220, 255); - drawText('Click to dispose / rebuild.', x, y++, 140, 160, 190); - drawText('--------------------------------', x, y++, 80, 100, 150); - const status = isDisposed ? 'OFFLINE' : 'ACTIVE'; - const sr = isDisposed ? 255 : 140; - const sg = isDisposed ? 100 : 255; - drawText(`GPU STATUS: ${status}`, x, y++, sr, sg, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + #### Overrides diff --git a/api/textmode.js/classes/TextmodeVector.md b/api/textmode.js/classes/TextmodeVector.md index 1460ac9a..b4e3fedb 100644 --- a/api/textmode.js/classes/TextmodeVector.md +++ b/api/textmode.js/classes/TextmodeVector.md @@ -23,100 +23,7 @@ Use [Textmodifier.createVector](Textmodifier/methods/createVector.md) to create ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Constructors diff --git a/api/textmode.js/classes/TextmodeVector/methods/add.md b/api/textmode.js/classes/TextmodeVector/methods/add.md index 4c4dc76a..a5ff479a 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/add.md +++ b/api/textmode.js/classes/TextmodeVector/methods/add.md @@ -38,100 +38,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -160,97 +67,5 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/copy.md b/api/textmode.js/classes/TextmodeVector/methods/copy.md index eb7efbad..c201a51c 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/copy.md +++ b/api/textmode.js/classes/TextmodeVector/methods/copy.md @@ -28,97 +28,5 @@ A new vector with the same components. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/cross.md b/api/textmode.js/classes/TextmodeVector/methods/cross.md index dc470d6f..5571f8f2 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/cross.md +++ b/api/textmode.js/classes/TextmodeVector/methods/cross.md @@ -36,100 +36,7 @@ A new vector containing the cross product. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -158,97 +65,5 @@ A new vector containing the cross product. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/dist.md b/api/textmode.js/classes/TextmodeVector/methods/dist.md index 7ad2576d..cda731eb 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dist.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dist.md @@ -36,100 +36,7 @@ Euclidean distance between the two points. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -158,97 +65,5 @@ Euclidean distance between the two points. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/div.md b/api/textmode.js/classes/TextmodeVector/methods/div.md index 0c534c07..f70a0188 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/div.md +++ b/api/textmode.js/classes/TextmodeVector/methods/div.md @@ -36,100 +36,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -155,100 +62,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -277,97 +91,5 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/dot.md b/api/textmode.js/classes/TextmodeVector/methods/dot.md index 55f27fd4..199ae927 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dot.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dot.md @@ -36,100 +36,7 @@ Dot product. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -158,97 +65,5 @@ Dot product. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/heading.md b/api/textmode.js/classes/TextmodeVector/methods/heading.md index ce9f52d5..bd43c21a 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/heading.md +++ b/api/textmode.js/classes/TextmodeVector/methods/heading.md @@ -31,97 +31,5 @@ Heading angle in degrees. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/limit.md b/api/textmode.js/classes/TextmodeVector/methods/limit.md index c0c42e02..4c3acbec 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/limit.md +++ b/api/textmode.js/classes/TextmodeVector/methods/limit.md @@ -34,97 +34,5 @@ This vector. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/mag.md b/api/textmode.js/classes/TextmodeVector/methods/mag.md index 48ab4b32..625ece54 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mag.md @@ -28,97 +28,5 @@ The vector length. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/magSq.md b/api/textmode.js/classes/TextmodeVector/methods/magSq.md index 7bd58c22..05b3c0f9 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/magSq.md +++ b/api/textmode.js/classes/TextmodeVector/methods/magSq.md @@ -30,97 +30,5 @@ The squared vector length. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/mult.md b/api/textmode.js/classes/TextmodeVector/methods/mult.md index eed1b0a1..1fb83d89 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mult.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mult.md @@ -36,100 +36,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -155,100 +62,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -277,97 +91,5 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/normalize.md b/api/textmode.js/classes/TextmodeVector/methods/normalize.md index abdbbba0..8142a039 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/normalize.md +++ b/api/textmode.js/classes/TextmodeVector/methods/normalize.md @@ -30,97 +30,5 @@ This vector. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/set.md b/api/textmode.js/classes/TextmodeVector/methods/set.md index f09872f1..3cad3dfa 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/set.md +++ b/api/textmode.js/classes/TextmodeVector/methods/set.md @@ -39,100 +39,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -161,97 +68,5 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/setMag.md b/api/textmode.js/classes/TextmodeVector/methods/setMag.md index 5cd6cd7f..da7e3ff5 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/setMag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/setMag.md @@ -36,97 +36,5 @@ This vector. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/TextmodeVector/methods/sub.md b/api/textmode.js/classes/TextmodeVector/methods/sub.md index ff32cfb2..46849413 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/sub.md +++ b/api/textmode.js/classes/TextmodeVector/methods/sub.md @@ -38,100 +38,7 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -160,97 +67,5 @@ This vector. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/canvas.md b/api/textmode.js/classes/Textmodifier/accessors/canvas.md index 0370cfdd..87d7817e 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/canvas.md +++ b/api/textmode.js/classes/Textmodifier/accessors/canvas.md @@ -28,83 +28,5 @@ Canvas containing the rendered output. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); - -t.canvas.title = 'Textmodifier.canvas'; -t.canvas.dataset.example = 'canvas'; -t.canvas.style.background = '#060713'; -t.canvas.style.outlineOffset = '-4px'; - -function updateCanvasElement() { - const hue = Math.floor((t.frameCount * 2) % 360); - t.canvas.style.outline = `3px solid hsl(${hue}, 90%, 62%)`; - t.canvas.style.boxShadow = `0 0 24px hsla(${hue}, 90%, 62%, 0.28)`; -} - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - updateCanvasElement(); - t.background(6, 8, 20); - - const cols = Math.floor(t.grid.cols / 2); - const rows = Math.floor(t.grid.rows / 2); - t.charColor(255, 190, 80); - for (let x = -cols; x <= cols; x += 4) { - t.push(); - t.translate(x, -rows + 1); - t.char('='); - t.point(); - t.translate(0, rows * 2 - 2); - t.point(); - t.pop(); - } - for (let y = -rows + 1; y < rows; y += 2) { - t.push(); - t.translate(-cols + 1, y); - t.char('|'); - t.point(); - t.translate(cols * 2 - 2, 0); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const size = `${t.canvas.width}x${t.canvas.height}`; - const title = t.canvas.title; - - drawText('TEXTMODIFIER.CANVAS', x, y++, 255, 190, 80); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DOM CANVAS ACCESS', x, y++, 100, 220, 255); - drawText('The getter returns the element.', x, y++, 140, 160, 190); - drawText('CSS and metadata update live.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SIZE: ${size}`, x, y++, 140, 190, 255); - drawText(`TITLE: ${title}`, x, y++, 150, 240, 170); - drawText('DATASET: canvas', x, y++, 150, 240, 170); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/conversions.md b/api/textmode.js/classes/Textmodifier/accessors/conversions.md index dbed9007..ea2c26a0 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/conversions.md +++ b/api/textmode.js/classes/Textmodifier/accessors/conversions.md @@ -31,50 +31,5 @@ when converting images/videos/canvases into textmode representations. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let hasBrightness = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - hasBrightness = t.conversions.has('brightness'); - t.char(hasBrightness ? '@' : '.'); - t.charColor(140, 220, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: IMAGE MAPPING', x, y++, 100, 220, 255); - drawText('Conversion registry maps sources.', x, y++, 140, 160, 190); - drawText('Built-ins can be queried.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(hasBrightness ? 'BRIGHTNESS: YES' : 'BRIGHTNESS: NO', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/errors.md b/api/textmode.js/classes/Textmodifier/accessors/errors.md index 17065ec7..e53a6bfb 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/errors.md +++ b/api/textmode.js/classes/Textmodifier/accessors/errors.md @@ -28,72 +28,5 @@ Built-in fatal error layer controller. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -let triggerError = false; -const labelLayer = t.layers.add(); - -window.addEventListener( - 'click', - () => { - triggerError = true; - }, - { once: true } -); - -t.draw(() => { - t.background(10, 12, 24); - - // Render a spinning neon cyan gear to demonstrate active draw loop - const time = t.frameCount * 0.05; - for (let i = 0; i < 8; i++) { - const angle = time + (i / 8) * Math.PI * 2; - t.push(); - t.translate(Math.cos(angle) * 8, Math.sin(angle) * 4); - t.charColor(0, 180, 255); - t.char('*'); - t.point(); - t.pop(); - } - - if (triggerError) { - throw new Error('This example intentionally triggers the error layer.'); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.ERRORS', x, y++, 255, 100, 100); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: AUTOMATED RUNTIME ERROR CAPTURE', x, y++, 100, 220, 255); - drawText('Shows fallback error overlay.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = Boolean(t.errors) ? 'TRUE' : 'FALSE'; - drawText(`ERRORS: ${state}`, x, y++, 140, 190, 255); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CLICK TO TRIGGER ERROR', x, y++, 255, 200, 100); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/filters.md b/api/textmode.js/classes/Textmodifier/accessors/filters.md index d4f2baf8..522085b3 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/filters.md +++ b/api/textmode.js/classes/Textmodifier/accessors/filters.md @@ -50,50 +50,5 @@ t.draw(() => { }); ``` -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let count = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - count = ['invert', 'grayscale', 'sepia'].filter((name) => t.filters.has(name)).length; - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILTERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FILTER REGISTRY', x, y++, 100, 220, 255); - drawText('Queries available filters.', x, y++, 140, 160, 190); - drawText('Registry is shared by output.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`BUILTINS: ${count}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/font.md b/api/textmode.js/classes/Textmodifier/accessors/font.md index fe355223..24542d3e 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/font.md +++ b/api/textmode.js/classes/Textmodifier/accessors/font.md @@ -31,52 +31,5 @@ Font or tileset used by the current drawing layer. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let index = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const chars = t.font.characters; - index = Math.floor(t.frameCount / 6) % chars.length; - t.char(chars[index].character); - t.charColor(255, 210, 120); - t.rect(8, 4); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FONT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACTIVE FONT', x, y++, 100, 220, 255); - drawText('Reads glyph metadata.', x, y++, 140, 160, 190); - drawText('Current glyph cycles.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`GLYPHS: ${t.font.characters.length}`, x, y++, 140, 255, 180); - drawText(`INDEX: ${index}`, x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md index 0a2fe2b0..555a899b 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md +++ b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md @@ -35,54 +35,7 @@ Number of frames rendered since the sketch started. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.push(); - t.translate(8, 2); - t.rotateZ(t.frameCount * 2); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 2); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FRAMECOUNT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FRAME COUNTER', x, y++, 100, 220, 255); - drawText('Counter increments each frame.', x, y++, 140, 160, 190); - drawText('Rotation uses frameCount.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FRAME: ${t.frameCount}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Set Signature @@ -107,55 +60,5 @@ point in time-based patterns. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.keyPressed((data) => { - if (data.key === ' ') t.frameCount = 0; -}); - -t.draw(() => { - t.background(6, 10, 22); - const phase = (t.frameCount % 120) / 120; - t.push(); - t.translate(-16 + phase * 32, 2); - t.char('@'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FRAMECOUNT2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESET COUNTER', x, y++, 100, 220, 255); - drawText('Space rewinds animation.', x, y++, 140, 160, 190); - drawText('frameCount is writable.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FRAME: ${t.frameCount}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/grid.md b/api/textmode.js/classes/Textmodifier/accessors/grid.md index 8f7133f6..f2e51333 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/grid.md +++ b/api/textmode.js/classes/Textmodifier/accessors/grid.md @@ -32,49 +32,5 @@ If no grid is set (e.g., before user setup()), returns `undefined`. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.charColor(50, 70, 100); - t.char('.'); - for (let x = -20; x <= 20; x += 4) t.line(x, -10, x, 10); - for (let y = -10; y <= 10; y += 2) t.line(-20, y, 20, y); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.GRID', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GRID METRICS', x, y++, 100, 220, 255); - drawText('Exposes rows, cols, and cells.', x, y++, 140, 160, 190); - drawText('Grid changes with window size.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`COLS: ${t.grid.cols}`, x, y++, 140, 255, 180); - drawText(`ROWS: ${t.grid.rows}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/height.md b/api/textmode.js/classes/Textmodifier/accessors/height.md index 327fd9c6..d21c95ea 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/height.md +++ b/api/textmode.js/classes/Textmodifier/accessors/height.md @@ -28,47 +28,5 @@ Canvas height in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.char('|'); - t.charColor(140, 220, 255); - t.rect(1, t.grid.rows); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.HEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CANVAS HEIGHT', x, y++, 100, 220, 255); - drawText('Returns pixel height.', x, y++, 140, 160, 190); - drawText('Line spans grid rows.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`HEIGHT: ${t.height}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md index c8a37b52..3220b3fb 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md @@ -28,51 +28,5 @@ Whether this instance has been destroyed. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (!t.isDisposed) t.destroy(); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char(t.isDisposed ? 'X' : '#'); - t.charColor(t.isDisposed ? 255 : 140, t.isDisposed ? 120 : 220, 180); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ISDISPOSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISPOSED FLAG', x, y++, 100, 220, 255); - drawText('Click calls destroy().', x, y++, 140, 160, 190); - drawText('Flag reports lifecycle state.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(t.isDisposed ? 'DISPOSED: YES' : 'DISPOSED: NO', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md index 59deb91d..ca385eac 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md @@ -28,55 +28,5 @@ Check if rendering is currently in progress for this frame. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let outsideFrame = false; -setInterval(() => { - outsideFrame = t.isRenderingFrame; -}, 120); - -t.draw(() => { - t.background(6, 10, 22); - t.char(t.isRenderingFrame ? '1' : '0'); - t.charColor(120, 220, 255); - t.rect(12, 8); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.ISRENDERINGFRAME', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FRAME GUARD FLAG', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const inside = t.isRenderingFrame ? 'TRUE' : 'FALSE'; - const outside = outsideFrame ? 'TRUE' : 'FALSE'; - drawText(`INSIDE: ${inside}`, x, y++, 140, 255, 180); - drawText(`OUTSIDE: ${outside}`, x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/layers.md b/api/textmode.js/classes/Textmodifier/accessors/layers.md index 1d2ecd8a..9cce2b55 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/layers.md +++ b/api/textmode.js/classes/Textmodifier/accessors/layers.md @@ -31,57 +31,5 @@ Each layer has its own grid, font, draw callback, and filters. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const topLayer = t.layers.add({ blendMode: 'additive' }); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -topLayer.draw(() => { - t.clear(); - t.char('+'); - t.charColor(255, 210, 120); - t.rect(8, 4); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 5); - topLayer.offset(Math.sin(t.frameCount * 0.03) * 30, 0); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LAYERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LAYER MANAGER', x, y++, 100, 220, 255); - drawText('Accesses the layer stack.', x, y++, 140, 160, 190); - drawText('Overlay layer moves in pixels.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`LAYERS: ${t.layers.all.length}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/loading.md b/api/textmode.js/classes/Textmodifier/accessors/loading.md index 6bbd6304..6d89cb03 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/loading.md +++ b/api/textmode.js/classes/Textmodifier/accessors/loading.md @@ -28,59 +28,5 @@ Built-in loading layer controller. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - loadingScreen: { transitionDuration: 300 }, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - t.loading.draw((ctx) => { - const tm = ctx.textmodifier; - tm.background(8, 10, 18); - tm.char('#'); - tm.charColor(100, 220, 255); - tm.rect(16, 4); - }); - await new Promise((resolve) => setTimeout(resolve, 400)); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char('@'); - t.charColor(140, 255, 180); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOADING', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOADING SCREEN', x, y++, 100, 220, 255); - drawText('Custom loading draw callback.', x, y++, 140, 160, 190); - drawText('Setup waits briefly.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STATUS: READY', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/millis.md b/api/textmode.js/classes/Textmodifier/accessors/millis.md index ecfad57c..e9b50702 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/millis.md +++ b/api/textmode.js/classes/Textmodifier/accessors/millis.md @@ -39,164 +39,11 @@ Milliseconds since the sketch started. ### Examples -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); + -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = t.millis / 1000; - const angle = (value % 6.28) * 1; - t.push(); - t.translate(8, 2); - t.rotateZ((angle * 180) / Math.PI); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MILLIS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ELAPSED TIME', x, y++, 100, 220, 255); - drawText('Numeric time drives motion.', x, y++, 140, 160, 190); - drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = (t.millis % 2000) / 1000; - const angle = (value % 6.28) * 1; - t.push(); - t.translate(8, 2); - t.rotateZ((angle * 180) / Math.PI); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MILLIS2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MODULO TIMER', x, y++, 100, 220, 255); - drawText('Numeric time drives motion.', x, y++, 140, 160, 190); - drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.keyPressed((data) => { - if (data.key === ' ') t.millis = 0; -}); - -t.draw(() => { - t.background(6, 10, 22); - const progress = (t.millis % 3000) / 3000; - for (let i = 0; i < 24; i++) { - t.push(); - t.translate(-12 + i, 3); - t.char(i / 24 < progress ? '#' : '.'); - t.charColor(140, 220, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MILLIS3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESET MILLIS', x, y++, 100, 220, 255); - drawText('Space resets elapsed millis.', x, y++, 140, 160, 190); - drawText('Progress bar loops every 3s.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MS: ${Math.floor(t.millis)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + + ## Set Signature @@ -221,55 +68,5 @@ affect the value returned by [secs](secs.md) since they are connected. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.sin(t.millis * 0.002); - const angle = (value % 6.28) * 1; - t.push(); - t.translate(8, 2); - t.rotateZ((angle * 180) / Math.PI); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MILLIS4', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SMOOTH OSCILLATOR', x, y++, 100, 220, 255); - drawText('Numeric time drives motion.', x, y++, 140, 160, 190); - drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/overlay.md b/api/textmode.js/classes/Textmodifier/accessors/overlay.md index 67ca6537..256d147a 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/overlay.md +++ b/api/textmode.js/classes/Textmodifier/accessors/overlay.md @@ -31,91 +31,5 @@ Overlay source image for the target canvas or video, when overlay mode is enable ### Example -```javascript -const sourceCanvas = document.createElement('canvas'); -const sourceCtx = sourceCanvas.getContext('2d'); - -document.body.style.margin = '0'; -document.body.style.overflow = 'hidden'; -sourceCanvas.style.position = 'fixed'; -sourceCanvas.style.inset = '0'; -sourceCanvas.style.width = '100vw'; -sourceCanvas.style.height = '100vh'; -sourceCanvas.style.display = 'block'; -document.body.appendChild(sourceCanvas); - -const t = textmode.create({ - canvas: sourceCanvas, - overlay: true, - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function resizeSourceCanvas() { - sourceCanvas.width = window.innerWidth; - sourceCanvas.height = window.innerHeight; -} - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function paintSourceCanvas() { - const pulse = t.frameCount * 0.035; - sourceCtx.fillStyle = '#050816'; - sourceCtx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); - sourceCtx.fillStyle = '#38bdf8'; - sourceCtx.fillRect(sourceCanvas.width * 0.24 + Math.sin(pulse) * 30, sourceCanvas.height * 0.42, 128, 82); - sourceCtx.fillStyle = '#f59e0b'; - sourceCtx.beginPath(); - sourceCtx.arc(sourceCanvas.width * 0.68, sourceCanvas.height * 0.5, 54, 0, Math.PI * 2); - sourceCtx.fill(); - sourceCtx.fillStyle = '#f8fafc'; - sourceCtx.fillRect(sourceCanvas.width * 0.33, sourceCanvas.height * 0.68, 150, 28); -} - -resizeSourceCanvas(); - -t.setup(() => { - if (!t.overlay) return; - t.overlay.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#050816'); -}); - -t.draw(() => { - paintSourceCanvas(); - t.clear(); - if (!t.overlay) return; - - t.image(t.overlay, t.grid.cols, t.grid.rows); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.OVERLAY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TARGET CANVAS SOURCE', x, y++, 100, 220, 255); - drawText('overlay samples sourceCanvas.', x, y++, 140, 160, 190); - drawText('Textmode renders above it.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = t.overlay ? 'READY' : 'WAIT'; - drawText(`OVERLAY: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - resizeSourceCanvas(); - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/secs.md b/api/textmode.js/classes/Textmodifier/accessors/secs.md index b284467d..cd59966f 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/secs.md +++ b/api/textmode.js/classes/Textmodifier/accessors/secs.md @@ -38,110 +38,9 @@ Seconds since the sketch started. ### Examples -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = t.secs; - const angle = (value % 6.28) * 1; - t.push(); - t.translate(8, 2); - t.rotateZ((angle * 180) / Math.PI); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SECS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ELAPSED SECONDS', x, y++, 100, 220, 255); - drawText('Numeric time drives motion.', x, y++, 140, 160, 190); - drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = t.secs % 4; - const angle = (value % 6.28) * 1; - t.push(); - t.translate(8, 2); - t.rotateZ((angle * 180) / Math.PI); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SECS2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOOPING SECONDS', x, y++, 100, 220, 255); - drawText('Numeric time drives motion.', x, y++, 140, 160, 190); - drawText('Rows stay fixed-width short.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + + ## Set Signature @@ -166,58 +65,5 @@ affect the value returned by [millis](millis.md) since they are connected. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let scrub = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseDragged(() => { - scrub = t.mouse.x === Number.NEGATIVE_INFINITY ? scrub : t.mouse.x / 10; -}); - -t.draw(() => { - t.background(6, 10, 22); - const value = t.mouseIsPressed ? scrub : t.secs; - t.push(); - t.translate(8, 2); - t.rotateZ(value * 40); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(10, 2); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SECS3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCRUB TIME', x, y++, 100, 220, 255); - drawText('Drag to scrub temporary time.', x, y++, 140, 160, 190); - drawText('Release to resume t.secs.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SECS: ${t.secs.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/accessors/width.md b/api/textmode.js/classes/Textmodifier/accessors/width.md index 8d8fee99..5b7d997b 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/width.md +++ b/api/textmode.js/classes/Textmodifier/accessors/width.md @@ -28,47 +28,5 @@ Canvas width in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.char('='); - t.charColor(140, 220, 255); - t.rect(t.grid.cols, 1); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.WIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CANVAS WIDTH', x, y++, 100, 220, 255); - drawText('Returns pixel width.', x, y++, 140, 160, 190); - drawText('Line spans grid columns.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`WIDTH: ${t.width}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/abs.md b/api/textmode.js/classes/Textmodifier/methods/abs.md index a6fdd1f0..c7e97159 100644 --- a/api/textmode.js/classes/Textmodifier/methods/abs.md +++ b/api/textmode.js/classes/Textmodifier/methods/abs.md @@ -34,74 +34,5 @@ Absolute value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let magnitude = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 7, 16); - raw = t.sin(t.frameCount * 0.045) * 12 + t.cos(t.frameCount * 0.021) * 3; - magnitude = t.abs(raw); - - t.char('-'); - t.charColor(60, 85, 125); - t.line(-24, 0, 24, 0); - t.char('|'); - t.line(0, -10, 0, 10); - - for (let i = 0; i <= t.round(magnitude); i++) { - const fade = t.norm(i, 0, 12); - t.push(); - t.translate(i, -5); - t.char('#'); - t.charColor(90 + fade * 150, 190, 255 - fade * 90); - t.point(); - t.translate(-i * 2, 10); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(255, 150, 110); - t.push(); - t.translate(t.round(raw), 0); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ABS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISTANCE FROM ZERO', x, y++, 100, 220, 255); - drawText('abs() removes the sign.', x, y++, 140, 160, 190); - drawText('Both sides draw equal magnitude.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`ABS: ${magnitude.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/acos.md b/api/textmode.js/classes/Textmodifier/methods/acos.md index 79d9cab9..0b469273 100644 --- a/api/textmode.js/classes/Textmodifier/methods/acos.md +++ b/api/textmode.js/classes/Textmodifier/methods/acos.md @@ -34,69 +34,5 @@ Angle in radians. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let input = 0; -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(8, 7, 16); - input = t.constrain(t.cos(t.frameCount * 0.035) + t.sin(t.frameCount * 0.019) * 0.25, -1, 1); - angle = t.acos(input); - const radius = 15; - const x = t.round(input * radius); - const y = t.round(t.sin(angle) * radius); - - t.char('.'); - t.charColor(45, 65, 100); - for (let i = 0; i <= 36; i++) { - const a = t.radians(i * 5); - t.push(); - t.translate(t.round(t.cos(a) * radius), t.round(t.sin(a) * radius)); - t.point(); - t.pop(); - } - - t.char('|'); - t.charColor(95, 145, 210); - t.line(x, 0, x, y); - t.char('*'); - t.charColor(255, 205, 100); - t.line(0, 0, x, y); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ACOS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: X VALUE TO ANGLE', x, y++, 100, 220, 255); - drawText('acos(value) reverses cosine.', x, y++, 140, 160, 190); - drawText('The vertical chord reveals arc.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${input.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md index 12cb54b7..290eada5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md @@ -39,59 +39,7 @@ Lighting uses RGB only, so any provided alpha value is ignored. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let channel = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - channel = 127.5 + 127.5 * Math.sin(time); - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - t.ambientLight(channel, channel, channel, channel); - t.rotateY(time * 40); - t.char('#'); - t.charColor(255, 255, 255); - t.sphere(7); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.AMBIENTLIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: AMBIENT LIGHT', x, y++, 100, 220, 255); - drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); - drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const level = Math.round(channel); - drawText(`RGBA:${level},${level},${level},${level}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md index 4923ff62..2e739e3d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md @@ -36,57 +36,7 @@ Current implementation supports affine TRS-style matrices (no perspective/shear) ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - const c = Math.cos(time); - const s = Math.sin(time); - t.push(); - t.translate(8, 1); - t.applyMatrix(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.APPLYMATRIX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM MATRIX', x, y++, 100, 220, 255); - drawText('Applies a 4x4 transform.', x, y++, 140, 160, 190); - drawText('Matrix rotates the rectangle.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.applyMatrix(...)', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/arc.md b/api/textmode.js/classes/Textmodifier/methods/arc.md index 44a7a1aa..0f3d4ca8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/arc.md +++ b/api/textmode.js/classes/Textmodifier/methods/arc.md @@ -40,59 +40,5 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let startDeg = 0; -let endDeg = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - startDeg = (time * 60) % 360; - endDeg = startDeg + 110 + Math.sin(time) * 35; - t.push(); - t.translate(8, 1); - t.char('#'); - t.charColor(140, 180, 255); - t.arc(22, 12, startDeg, endDeg); - t.charColor(60, 70, 100); - t.line(0, 0, Math.cos((startDeg * Math.PI) / 180) * 11, Math.sin((startDeg * Math.PI) / 180) * 6); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ARC', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PARTIAL ELLIPSE', x, y++, 100, 220, 255); - drawText('Animated start and end angles.', x, y++, 140, 160, 190); - drawText('Guide line marks the start.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`START: ${startDeg.toFixed(1)}`, x, y++, 255, 210, 120); - drawText(`END: ${endDeg.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/asin.md b/api/textmode.js/classes/Textmodifier/methods/asin.md index dbf91b36..ae850bc9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/asin.md +++ b/api/textmode.js/classes/Textmodifier/methods/asin.md @@ -34,67 +34,5 @@ Angle in radians. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let input = 0; -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 10, 18); - input = t.constrain(t.sin(t.frameCount * 0.04) + t.cos(t.frameCount * 0.017) * 0.25, -1, 1); - angle = t.asin(input); - const radius = 14; - - for (let i = -16; i <= 16; i++) { - const a = t.radians(i * 6); - t.push(); - t.translate(t.round(t.cos(a) * radius), t.round(t.sin(a) * radius)); - t.char('.'); - t.charColor(50, 70, 105); - t.point(); - t.pop(); - } - - t.char('-'); - t.charColor(80, 130, 180); - t.line(-radius, t.round(input * radius), radius, t.round(input * radius)); - t.char('*'); - t.charColor(255, 210, 100); - t.line(0, 0, t.round(t.cos(angle) * radius), t.round(t.sin(angle) * radius)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ASIN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VALUE BACK TO ANGLE', x, y++, 100, 220, 255); - drawText('asin(value) reverses sine.', x, y++, 140, 160, 190); - drawText('The horizontal value finds a ray.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${input.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/atan.md b/api/textmode.js/classes/Textmodifier/methods/atan.md index 395ba76e..d0af2c41 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan.md @@ -34,67 +34,5 @@ Angle in radians. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let slope = 0; -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - slope = t.sin(t.frameCount * 0.035) * 3 + t.cos(t.frameCount * 0.021) * 1.2; - angle = t.atan(slope); - - for (let i = -4; i <= 4; i++) { - const s = i * 0.6; - const a = t.atan(s); - t.char('.'); - t.charColor(45, 65, 100); - t.line(0, 0, t.round(t.cos(a) * 18), t.round(t.sin(a) * 18)); - } - - t.char('*'); - t.charColor(255, 215, 100); - t.line(0, 0, t.round(t.cos(angle) * 20), t.round(t.sin(angle) * 20)); - t.char('@'); - t.push(); - t.translate(t.round(t.cos(angle) * 20), t.round(t.sin(angle) * 20)); - t.charColor(120, 255, 170); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ATAN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SLOPE TO ANGLE', x, y++, 100, 220, 255); - drawText('atan(slope) compresses extremes.', x, y++, 140, 160, 190); - drawText('Steep values still fit a ray.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SLOPE: ${slope.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`ANGLE: ${angle.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/atan2.md b/api/textmode.js/classes/Textmodifier/methods/atan2.md index 9caf12da..88e5c82a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan2.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan2.md @@ -35,68 +35,5 @@ Angle in radians. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - const targetX = t.sin(t.frameCount * 0.027) * 18 + t.cos(t.frameCount * 0.05) * 4; - const targetY = t.cos(t.frameCount * 0.039) * 8 + t.sin(t.frameCount * 0.043) * 3; - angle = t.atan2(targetY, targetX); - - t.char('.'); - t.charColor(45, 60, 95); - for (let i = 0; i < 40; i++) { - const a = (i / 40) * t.radians(360); - t.push(); - t.translate(t.round(t.cos(a) * 16), t.round(t.sin(a) * 8)); - t.point(); - t.pop(); - } - - t.char('*'); - t.charColor(255, 215, 100); - t.line(0, 0, t.round(t.cos(angle) * 22), t.round(t.sin(angle) * 11)); - t.char('@'); - t.charColor(120, 255, 170); - t.push(); - t.translate(t.round(targetX), t.round(targetY)); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ATAN2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POINTING AT A TARGET', x, y++, 100, 220, 255); - drawText('atan2(y, x) keeps quadrants.', x, y++, 140, 160, 190); - drawText('The ray tracks the green target.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ANGLE: ${angle.toFixed(2)} rad`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/background.md b/api/textmode.js/classes/Textmodifier/methods/background.md index c9ef5c28..4e43d495 100644 --- a/api/textmode.js/classes/Textmodifier/methods/background.md +++ b/api/textmode.js/classes/Textmodifier/methods/background.md @@ -30,58 +30,7 @@ Current background color. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let r = 0; -let g = 0; -let b = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.03; - r = Math.round(40 + 30 * Math.sin(time)); - g = Math.round(30 + 30 * Math.sin(time + 2)); - b = Math.round(60 + 40 * Math.sin(time + 4)); - t.background(r, g, b); - t.char('#'); - t.charColor(240, 245, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BACKGROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CANVAS COLOR', x, y++, 100, 220, 255); - drawText('Sets and reads scene backdrop.', x, y++, 140, 160, 190); - drawText('RGB values animate softly.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RGB: ${r},${g},${b}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -104,53 +53,7 @@ Set the background color using a grayscale value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let gray = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - gray = Math.round(30 + 40 * Math.sin(t.frameCount * 0.03)); - t.background(gray); - t.char('@'); - t.charColor(255, 210, 120); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BACKGROUND2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GRAY BACKGROUND', x, y++, 100, 220, 255); - drawText('One number sets R, G, and B.', x, y++, 140, 160, 190); - drawText('Gray value animates.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`GRAY: ${gray}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -179,53 +82,7 @@ Set the background color using RGB(A) values. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let useBlue = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - useBlue = Math.floor(t.frameCount / 90) % 2 === 0; - t.background(useBlue ? '#10183a' : '#301820'); - t.char(useBlue ? 'B' : 'R'); - t.charColor(255, 230, 140); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BACKGROUND3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HEX BACKGROUND', x, y++, 100, 220, 255); - drawText('Hex strings set the color.', x, y++, 140, 160, 190); - drawText('Mode alternates blue and red.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(useBlue ? 'HEX: BLUE' : 'HEX: RED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -247,52 +104,5 @@ Set the background color using a CSS string or TextmodeColor object. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const colorA = t.color(32, 12, 20); -const colorB = t.color(10, 24, 48); -let useA = true; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - useA = Math.floor(t.frameCount / 90) % 2 === 0; - t.background(useA ? colorA : colorB); - t.char(useA ? 'A' : 'B'); - t.charColor(255, 230, 140); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BACKGROUND4', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: COLOR OBJECT', x, y++, 100, 220, 255); - drawText('Reusable TextmodeColor values.', x, y++, 140, 160, 190); - drawText('Background switches objects.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(useA ? 'ACTIVE: COLOR A' : 'ACTIVE: COLOR B', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/beginShape.md b/api/textmode.js/classes/Textmodifier/methods/beginShape.md index cd82d184..36cd1458 100644 --- a/api/textmode.js/classes/Textmodifier/methods/beginShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/beginShape.md @@ -33,66 +33,5 @@ Call [vertex](vertex.md) one or more times, then call [endShape](endShape.md) to ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let points = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.025; - const spikes = 7; - const outer = 16 + Math.sin(time) * 2; - const inner = 6 + Math.cos(time * 1.4) * 1.5; - points = spikes * 2; - - t.push(); - t.rotateZ(time * 18); - t.char('*'); - t.charColor(255, 220, 96); - t.cellColor(24, 16, 4); - t.lineWeight(1.4); - t.beginShape(); - for (let i = 0; i < points; i++) { - const angle = t.radians(i * (360 / points) - 90); - const radius = i % 2 === 0 ? outer : inner; - t.vertex(Math.cos(angle) * radius, Math.sin(angle) * radius); - } - t.endShape('close'); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BEGINSHAPE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM 2D POLYGON', x, y++, 100, 220, 255); - drawText('Recorded vertices form one loop.', x, y++, 140, 160, 190); - drawText('Line state is captured per vertex.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VERTICES: ${points}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md index 8e765cc5..9c1dddd0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md +++ b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md @@ -48,59 +48,5 @@ The curve thickness is controlled by the current [lineWeight](lineWeight.md) set ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.025; - const cp1x = -8 + Math.sin(time) * 6; - const cp1y = -7; - const cp2x = 8 + Math.cos(time * 0.8) * 6; - const cp2y = 7; - t.push(); - t.translate(7, 1); - t.charColor(60, 70, 100); - t.char('.'); - t.line(-14, 0, cp1x, cp1y); - t.line(14, 0, cp2x, cp2y); - t.char('#'); - t.charColor(140, 220, 255); - t.bezierCurve(-14, 0, cp1x, cp1y, cp2x, cp2y, 14, 0); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BEZIERCURVE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUBIC CURVE', x, y++, 100, 220, 255); - drawText('Two control points bend path.', x, y++, 140, 160, 190); - drawText('Guide lines show handles.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.bezierCurve(...)', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/box.md b/api/textmode.js/classes/Textmodifier/methods/box.md index 126799eb..727df7a6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/box.md +++ b/api/textmode.js/classes/Textmodifier/methods/box.md @@ -37,61 +37,5 @@ Draw a box mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.box(9, 7, 8); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BOX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D BOX', x, y++, 100, 220, 255); - drawText('Width, height, and depth vary.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/camera.md b/api/textmode.js/classes/Textmodifier/methods/camera.md index e13b5ed5..7ed9d365 100644 --- a/api/textmode.js/classes/Textmodifier/methods/camera.md +++ b/api/textmode.js/classes/Textmodifier/methods/camera.md @@ -49,58 +49,5 @@ Set an explicit camera transform for subsequent draw calls. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let eyeX = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - eyeX = Math.sin(time) * 24; - t.perspective(58, 0.1, 4096); - t.camera(eyeX, 8, 42, 0, 0, 0); - t.ambientLight(25, 28, 36); - t.pointLight([255, 210, 140], { x: 20, y: -18, z: 28 }); - t.push(); - t.rotateY(time * 30); - t.char('#'); - t.charColor(140, 220, 255); - t.box(8, 8, 8); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CAMERA', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET VIEW CAMERA', x, y++, 100, 220, 255); - drawText('Eye position moves left/right.', x, y++, 140, 160, 190); - drawText('Target remains at origin.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`EYE X: ${eyeX.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ceil.md b/api/textmode.js/classes/Textmodifier/methods/ceil.md index 9a852b60..8933adcb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ceil.md +++ b/api/textmode.js/classes/Textmodifier/methods/ceil.md @@ -34,63 +34,5 @@ Smallest integer greater than or equal to the value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let snapped = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(7, 6, 17); - raw = t.norm(t.sin(t.frameCount * 0.045) + t.cos(t.frameCount * 0.017) * 0.25, -1.25, 1.25) * 14; - snapped = t.ceil(raw); - - for (let i = 0; i < 15; i++) { - const active = i < snapped; - t.push(); - t.translate(-16 + i * 2, 6 - i * 0.35); - t.char(active ? '#' : '.'); - t.charColor(active ? 120 + i * 8 : 50, active ? 245 : 65, active ? 170 : 95); - t.rect(1, active ? 2 + i * 0.2 : 1); - t.pop(); - } - - t.char('-'); - t.charColor(255, 150, 120); - t.line(-18, 8 - raw, 16, 8 - raw); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CEIL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SNAP UP', x, y++, 100, 220, 255); - drawText('ceil() counts partial cells full.', x, y++, 140, 160, 190); - drawText('Green blocks anticipate growth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`CEIL: ${snapped}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/cellColor.md b/api/textmode.js/classes/Textmodifier/methods/cellColor.md index b0c66b86..5e9bd742 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cellColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cellColor.md @@ -30,54 +30,7 @@ Current cell color. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - t.cellColor(value, 50, 110); - t.charColor(240, 245, 255); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CELLCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CELL BACKGROUND', x, y++, 100, 220, 255); - drawText('Sets the cell background color.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`R: ${value}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -100,54 +53,7 @@ Set the cell background color using a grayscale value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - t.cellColor(value); - t.charColor(240, 245, 255); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CELLCOLOR2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GRAY CELL BACKGROUND', x, y++, 100, 220, 255); - drawText('One number sets cellColor.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`GRAY: ${value}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -176,54 +82,7 @@ Set the cell background color using RGB(A) values. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - t.cellColor(value > 80 ? '#14385f' : '#301820'); - t.charColor(240, 245, 255); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CELLCOLOR3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HEX CELL BACKGROUND', x, y++, 100, 220, 255); - drawText('Hex strings set cellColor.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(value > 80 ? 'HEX: BLUE' : 'HEX: RED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -245,52 +104,5 @@ Set the cell background color using a CSS string or TextmodeColor object. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - const c = t.color(value, 40, 90); - t.cellColor(c); - t.charColor(240, 245, 255); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CELLCOLOR4', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CELL COLOR OBJECT', x, y++, 100, 220, 255); - drawText('TextmodeColor can be reused.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`R: ${value}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/char.md b/api/textmode.js/classes/Textmodifier/methods/char.md index 9ef21c7d..aad5b9dc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/char.md +++ b/api/textmode.js/classes/Textmodifier/methods/char.md @@ -30,54 +30,7 @@ The active character string. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const glyphs = ['A', 'B', 'C', '#']; -let glyph = 'A'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - glyph = glyphs[Math.floor(t.frameCount / 45) % glyphs.length]; - t.char(glyph); - t.charColor(255, 210, 120); - t.rect(8, 4); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CHAR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACTIVE GLYPH', x, y++, 100, 220, 255); - drawText('Sets the glyph for drawing.', x, y++, 140, 160, 190); - drawText('The selected glyph cycles.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CHAR: ' + glyph, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -100,50 +53,5 @@ Accepts a single character string or a character index in the current font. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let index = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - index = Math.floor(t.frameCount / 5) % 128; - t.char(index); - t.charColor(255, 210, 120); - t.rect(8, 4); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CHAR2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH INDEX', x, y++, 100, 220, 255); - drawText('Numeric indices select glyphs.', x, y++, 140, 160, 190); - drawText('Index cycles through the font.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INDEX: ${index}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/charColor.md b/api/textmode.js/classes/Textmodifier/methods/charColor.md index 87a560e5..d76fffa8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/charColor.md @@ -30,56 +30,7 @@ Current character color. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let current = t.color(255, 255, 255); - -t.draw(() => { - t.background(6, 10, 22); - const r = Math.round(150 + 105 * Math.sin(t.frameCount * 0.04)); - const g = Math.round(150 + 105 * Math.cos(t.frameCount * 0.03)); - t.charColor(r, g, 180); - current = t.charColor(); - t.char('#'); - t.rect(14, 6); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CHARCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CHARACTER COLOR', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const rgb = current.r + ',' + current.g + ',' + current.b; - drawText(`RGB: ${rgb}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -102,53 +53,7 @@ Set the character color using a grayscale value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - t.charColor(value, 220); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CHARCOLOR2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GRAY GLYPH COLOR', x, y++, 100, 220, 255); - drawText('Gray plus alpha overload.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`GRAY: ${value}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -177,53 +82,7 @@ Set the character color using RGB(A) values. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - t.charColor(value > 80 ? '#facc15' : '#38bdf8'); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CHARCOLOR3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HEX GLYPH COLOR', x, y++, 100, 220, 255); - drawText('Hex strings color glyphs.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(value > 80 ? 'HEX: GOLD' : 'HEX: CYAN', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -245,54 +104,5 @@ Set the character color using a CSS string or TextmodeColor object. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const colorA = t.color('#64ffd0'); -const colorB = t.color('#ffc878'); -let active = 'colorA'; - -t.draw(() => { - t.background(6, 10, 22); - const useA = Math.floor(t.frameCount / 45) % 2 === 0; - active = useA ? 'colorA' : 'colorB'; - t.charColor(useA ? colorA : colorB); - t.char('@'); - t.rotateZ(t.frameCount * 2); - t.rect(10, 10); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CHARCOLOR4', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: COLOR OBJECT INPUT', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ACTIVE: ${active}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/charRotation.md b/api/textmode.js/classes/Textmodifier/methods/charRotation.md index 5223552d..42ba0b81 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charRotation.md +++ b/api/textmode.js/classes/Textmodifier/methods/charRotation.md @@ -34,56 +34,5 @@ Current rotation angle in degrees when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - angle = (t.frameCount * 2) % 360; - for (let i = 0; i < 8; i++) { - t.push(); - t.translate((i - 3.5) * 3, 0); - t.charRotation(angle + i * 30); - t.char('+'); - t.charColor(140, 220, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CHARROTATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ROTATE GLYPHS', x, y++, 100, 220, 255); - drawText('Rotates characters in cells.', x, y++, 140, 160, 190); - drawText('Transform matrix is unchanged.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ANGLE: ${angle}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/clamp.md b/api/textmode.js/classes/Textmodifier/methods/clamp.md index b79ff75c..ef560d34 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/clamp.md @@ -41,96 +41,5 @@ The clamped value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let clamped = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(8, 9, 17); - const low = -10; - const high = 10; - const railWidth = high - low + 1; - raw = Math.sin(t.frameCount * 0.045) * 18 + t.mouse.x * 0.28; - clamped = t.clamp(raw, low, high); - - t.char('.'); - t.charColor(38, 50, 80); - for (let x = -22; x <= 22; x += 2) drawPoint(x, 0); - - drawBand((low + high) / 2, -5, railWidth, 1, 80, 130, 190); - drawBand((low + high) / 2, 5, railWidth, 1, 80, 130, 190); - drawBand(low, 0, 1, 11, 55, 120, 155); - drawBand(high, 0, 1, 11, 55, 120, 155); - - t.push(); - t.translate(raw, -5); - t.char('o'); - t.charColor(230, 90, 90); - t.point(); - t.pop(); - - t.push(); - t.translate(clamped, 0); - t.char('#'); - t.charColor(110, 245, 170); - t.rect(2, 11); - t.pop(); - - t.char('*'); - t.charColor(255, 205, 90); - t.line(raw, -5, clamped, 0); - t.line(raw, 5, clamped, 0); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CLAMP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HARD LIMITS', x, y++, 100, 220, 255); - drawText('Raw red input can leave the gate.', x, y++, 140, 160, 190); - drawText('clamp() pins output to the rails.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(1)}`, x, y++, 255, 150, 120); - drawText(`CLAMPED: ${clamped.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/clear.md b/api/textmode.js/classes/Textmodifier/methods/clear.md index 4413c6cd..3cb7ad90 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clear.md +++ b/api/textmode.js/classes/Textmodifier/methods/clear.md @@ -28,60 +28,5 @@ Used to clear the layer at the start of its drawing cycle. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let clearEnabled = true; - -t.mouseClicked(() => { - clearEnabled = !clearEnabled; - if (clearEnabled) t.clear(); -}); - -t.draw(() => { - if (clearEnabled) t.clear(); - const time = t.frameCount * 0.05; - t.push(); - t.translate(Math.cos(time) * 15, Math.sin(time) * 6); - t.charColor(255, 225, 140); - t.char('#'); - t.rect(4, 2); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CLEAR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLEAR LAYER BUFFER', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = clearEnabled ? 'ON' : 'OFF'; - drawText(`CLEAR: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/color.md b/api/textmode.js/classes/Textmodifier/methods/color.md index cc37b2f1..1d5c2dd8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/color.md +++ b/api/textmode.js/classes/Textmodifier/methods/color.md @@ -37,54 +37,7 @@ A TextmodeColor instance ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - const c = t.color(value, 180); - t.charColor(c); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MAKE COLOR', x, y++, 100, 220, 255); - drawText('Creates reusable gray color.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -115,62 +68,7 @@ A TextmodeColor instance ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const goldLayer = t.layers.add(); -const cyan = t.color(100, 220, 255); -const gold = t.color(255, 225, 140, 150); - -t.draw(() => { - t.background(6, 10, 22); - t.charColor(cyan); - t.char('o'); - t.translate(Math.cos(t.frameCount * 0.03) * 10, 0); - t.ellipse(12, 10); -}); - -goldLayer.draw(() => { - t.clear(); - t.charColor(gold); - t.char('#'); - t.rect(12, 8); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.COLOR2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RGBA COLOR OBJECT', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('RGBA ALPHA: 150', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -197,51 +95,5 @@ A TextmodeColor instance ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - value = Math.round(80 + 80 * Math.sin(t.frameCount * 0.04)); - t.char('#'); - const c = t.color(value > 80 ? '#facc15' : '#38bdf8'); - t.charColor(c); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COLOR3', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HEX COLOR', x, y++, 100, 220, 255); - drawText('Creates color from hex string.', x, y++, 140, 160, 190); - drawText('The value pulses every frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(value > 80 ? 'HEX: GOLD' : 'HEX: CYAN', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/colorMode.md b/api/textmode.js/classes/Textmodifier/methods/colorMode.md index 10faba1d..b9bab9bf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/colorMode.md +++ b/api/textmode.js/classes/Textmodifier/methods/colorMode.md @@ -30,103 +30,7 @@ Current color mode and channel maxes. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const glyphs = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.colorMode('rgb'); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function paintCell(mode, u, v, wave, curl, hue) { - const shimmer = (wave + curl) * 0.5; - if (mode === 'rgb') { - t.colorMode('rgb', 255); - t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); - t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); - return; - } - if (mode === 'hsb') { - t.colorMode('hsb', 360, 100, 100, 1); - t.cellColor(hue, 92, 2 + 24 * wave); - t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); - return; - } - t.colorMode('hsl', 360, 100, 100, 1); - t.cellColor(hue, 65, 8 + 45 * curl); - t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); -} - -function paintPanel(mode, index, left, top, panelWidth, height, time) { - const x0 = left + index * panelWidth; - const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; - const y0 = top + 11; - for (let y = y0; y < top + height - 2; y++) { - t.push(); - t.translate(x0, y); - for (let x = x0; x < x1; x++) { - const u = (x - x0) / Math.max(1, x1 - x0 - 1); - const v = (y - y0) / Math.max(1, height - 13); - const dx = u * 2 - 1; - const dy = v * 2 - 1; - const radius = Math.sqrt(dx * dx + dy * dy); - const angle = Math.atan2(dy, dx); - const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; - const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; - const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; - const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; - t.char(glyph); - paintCell(mode, u, v, wave, curl, hue); - t.point(); - t.translate(1, 0); - } - t.pop(); - } -} - -t.draw(() => { - t.colorMode('rgb'); - t.background(4, 6, 14); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - const panelWidth = Math.floor(t.grid.cols / 3); - const time = t.frameCount * 0.035; - paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); - drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); - drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); - drawText('Same hue, different third value.', x, y++, 140, 160, 190); - drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -153,103 +57,7 @@ alpha, defaulting to the selected mode's alpha max. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const glyphs = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.colorMode('rgb'); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function paintCell(mode, u, v, wave, curl, hue) { - const shimmer = (wave + curl) * 0.5; - if (mode === 'rgb') { - t.colorMode('rgb', 255); - t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); - t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); - return; - } - if (mode === 'hsb') { - t.colorMode('hsb', 360, 100, 100, 1); - t.cellColor(hue, 92, 2 + 24 * wave); - t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); - return; - } - t.colorMode('hsl', 360, 100, 100, 1); - t.cellColor(hue, 65, 8 + 45 * curl); - t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); -} - -function paintPanel(mode, index, left, top, panelWidth, height, time) { - const x0 = left + index * panelWidth; - const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; - const y0 = top + 11; - for (let y = y0; y < top + height - 2; y++) { - t.push(); - t.translate(x0, y); - for (let x = x0; x < x1; x++) { - const u = (x - x0) / Math.max(1, x1 - x0 - 1); - const v = (y - y0) / Math.max(1, height - 13); - const dx = u * 2 - 1; - const dy = v * 2 - 1; - const radius = Math.sqrt(dx * dx + dy * dy); - const angle = Math.atan2(dy, dx); - const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; - const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; - const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; - const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; - t.char(glyph); - paintCell(mode, u, v, wave, curl, hue); - t.point(); - t.translate(1, 0); - } - t.pop(); - } -} - -t.draw(() => { - t.colorMode('rgb'); - t.background(4, 6, 14); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - const panelWidth = Math.floor(t.grid.cols / 3); - const time = t.frameCount * 0.035; - paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); - drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); - drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); - drawText('Same hue, different third value.', x, y++, 140, 160, 190); - drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -280,100 +88,5 @@ Set how numeric color inputs are interpreted with per-channel ranges. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const glyphs = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.colorMode('rgb'); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function paintCell(mode, u, v, wave, curl, hue) { - const shimmer = (wave + curl) * 0.5; - if (mode === 'rgb') { - t.colorMode('rgb', 255); - t.cellColor(4 + 34 * wave, 8 + 30 * u, 18 + 52 * v); - t.charColor(70 + 185 * u, 70 + 185 * wave, 250 - 130 * v); - return; - } - if (mode === 'hsb') { - t.colorMode('hsb', 360, 100, 100, 1); - t.cellColor(hue, 92, 2 + 24 * wave); - t.charColor(hue + shimmer * 70, 95, 10 + 90 * wave); - return; - } - t.colorMode('hsl', 360, 100, 100, 1); - t.cellColor(hue, 65, 8 + 45 * curl); - t.charColor(hue + shimmer * 120, 95, 8 + 84 * wave); -} - -function paintPanel(mode, index, left, top, panelWidth, height, time) { - const x0 = left + index * panelWidth; - const x1 = index === 2 ? left + t.grid.cols : x0 + panelWidth; - const y0 = top + 11; - for (let y = y0; y < top + height - 2; y++) { - t.push(); - t.translate(x0, y); - for (let x = x0; x < x1; x++) { - const u = (x - x0) / Math.max(1, x1 - x0 - 1); - const v = (y - y0) / Math.max(1, height - 13); - const dx = u * 2 - 1; - const dy = v * 2 - 1; - const radius = Math.sqrt(dx * dx + dy * dy); - const angle = Math.atan2(dy, dx); - const wave = (Math.sin(radius * 12 - time * 2.4 + angle * 5) + 1) * 0.5; - const curl = (Math.sin((u - v) * 10 + time + index * 1.7) + 1) * 0.5; - const hue = (angle * 180) / Math.PI + 180 + time * 42 + index * 36; - const glyph = glyphs[Math.floor((wave * 0.65 + curl * 0.35) * (glyphs.length - 1))]; - t.char(glyph); - paintCell(mode, u, v, wave, curl, hue); - t.point(); - t.translate(1, 0); - } - t.pop(); - } -} - -t.draw(() => { - t.colorMode('rgb'); - t.background(4, 6, 14); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - const panelWidth = Math.floor(t.grid.cols / 3); - const time = t.frameCount * 0.035; - paintPanel('rgb', 0, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsb', 1, left, top, panelWidth, t.grid.rows, time); - paintPanel('hsl', 2, left, top, panelWidth, t.grid.rows, time); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('RGB: CHANNEL MIXING', x, y++, 255, 150, 120); - drawText('HSB: BRIGHTNESS TO BLACK', x, y++, 120, 220, 255); - drawText('HSL: LIGHTNESS TO WHITE', x, y++, 210, 170, 255); - drawText('Same hue, different third value.', x, y++, 140, 160, 190); - drawText('Glyphs and cells both respond.', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/cone.md b/api/textmode.js/classes/Textmodifier/methods/cone.md index 746e3c6b..d7fb7e06 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cone.md +++ b/api/textmode.js/classes/Textmodifier/methods/cone.md @@ -33,61 +33,5 @@ Draw a cone mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.cone(5, 12); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CONE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D CONE', x, y++, 100, 220, 255); - drawText('Radius and height define form.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/constrain.md b/api/textmode.js/classes/Textmodifier/methods/constrain.md index df0e0c71..cdb8d3d0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/constrain.md +++ b/api/textmode.js/classes/Textmodifier/methods/constrain.md @@ -39,94 +39,5 @@ The constrained value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let freeX = 0; -let boundedX = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(7, 11, 18); - const leftRail = -14; - const rightRail = 14; - const railWidth = rightRail - leftRail + 1; - freeX = Math.cos(t.frameCount * 0.035) * 20 + t.mouse.x * 0.18; - boundedX = t.constrain(freeX, leftRail, rightRail); - - drawBand((leftRail + rightRail) / 2, -7, railWidth, 1, 54, 70, 100); - drawBand((leftRail + rightRail) / 2, 7, railWidth, 1, 54, 70, 100); - drawBand(leftRail, 0, 1, 15, 90, 165, 215); - drawBand(rightRail, 0, 1, 15, 90, 165, 215); - - for (let i = 0; i < 9; i++) { - const y = -6 + i * 1.5; - const offset = Math.sin(t.frameCount * 0.04 + i) * 2; - const x = t.constrain(boundedX + offset, leftRail, rightRail); - const heat = Math.round(t.constrain(Math.abs(freeX - boundedX) * 20, 0, 255)); - t.char(i % 2 === 0 ? '*' : '+'); - t.charColor(255 - heat * 0.4, 170 + heat * 0.2, 120 + heat * 0.5); - drawPoint(x, y); - } - - t.push(); - t.translate(freeX, -9); - t.char('x'); - t.charColor(255, 95, 95); - t.point(); - t.pop(); - - t.char('.'); - t.charColor(255, 220, 120); - t.line(freeX, -9, boundedX, -7); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CONSTRAIN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RANGE SAFETY', x, y++, 100, 220, 255); - drawText('constrain() keeps motion in bounds.', x, y++, 140, 160, 190); - drawText('The red target may drift outside.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FREE X: ${freeX.toFixed(1)}`, x, y++, 255, 150, 120); - drawText(`SAFE X: ${boundedX.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/cos.md b/api/textmode.js/classes/Textmodifier/methods/cos.md index abaedc09..e7c27268 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cos.md +++ b/api/textmode.js/classes/Textmodifier/methods/cos.md @@ -36,67 +36,5 @@ Cosine of the angle. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let phase = 0; -let sample = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 15); - phase = t.frameCount * 0.045; - sample = t.cos(phase); - const rings = 9; - - for (let i = rings; i >= 1; i--) { - const wave = t.norm(t.cos(phase + i * 0.45), -1, 1); - const rx = 2 + i * 3 + wave * 3; - const ry = 1 + i * 1.2 + wave * 2; - t.push(); - t.char(i % 2 === 0 ? '.' : '+'); - t.charColor(70 + wave * 140, 120 + wave * 90, 230); - t.ellipse(rx, ry); - t.pop(); - } - - t.push(); - t.translate(t.round(sample * 18), 0); - t.char('@'); - t.charColor(255, 215, 110); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.COS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PHASED BREATHING', x, y++, 100, 220, 255); - drawText('cos() starts at 1, then cycles.', x, y++, 140, 160, 190); - drawText('Rings expand by cosine phase.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`COS: ${sample.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createCamera.md b/api/textmode.js/classes/Textmodifier/methods/createCamera.md index bdc10d38..ea025dd7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/createCamera.md @@ -29,62 +29,5 @@ reapplied via [setCamera](setCamera.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let camera; -let eyeX = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - t.perspective(58, 0.1, 4096); - camera = t.createCamera(); -}); - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - eyeX = Math.cos(time) * 28; - camera.setPosition(eyeX, 10, 38).lookAt(0, 0, 0); - t.setCamera(camera); - t.ambientLight(25, 28, 36); - t.pointLight([255, 210, 140], { x: 18, y: -16, z: 28 }); - t.rotateY(time * 25); - t.char('@'); - t.charColor(140, 220, 255); - t.sphere(6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CREATECAMERA', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MUTABLE CAMERA', x, y++, 100, 220, 255); - drawText('createCamera returns an object.', x, y++, 140, 160, 190); - drawText('setCamera applies its state.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`EYE X: ${eyeX.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md b/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md index 4e8b668c..d493c89a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md @@ -42,80 +42,5 @@ This compatibility alias creates a fragment-only geometry shader for use with ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let shaderObj; -let glyphA = [0, 0, 0]; -let glyphB = [0, 0, 0]; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} -t.setup(async () => { - glyphA = t.font.characterMap.get('#')?.color ?? t.font.characters[1].color; - glyphB = t.font.characterMap.get('@')?.color ?? t.font.characters[2].color; - shaderObj = await t.createFilterShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -uniform vec3 u_glyphA; -uniform vec3 u_glyphB; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - float stripe = step(0.5, fract((v_uv.x + u_time) * 10.0)); - vec3 glyphId = mix(u_glyphA, u_glyphB, stripe); - vec3 primary = mix(vec3(0.3, 0.8, 1.0), vec3(1.0, 0.42, 0.22), stripe); - o_character = vec4(glyphId.xy, 0.0, 0.0); - o_primaryColor = vec4(primary, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.08 + stripe * 0.12, 1.0); -}`); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (shaderObj) { - const time = t.frameCount * 0.02; - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - t.shader(shaderObj); - t.setUniforms({ u_time: time * 0.1, u_glyphA: glyphA, u_glyphB: glyphB }); - t.push(); - t.rotateZ(time * 40); - t.rect(16, 8); - t.pop(); - t.resetShader(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CREATEFILTERSHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: COMPAT ALIAS', x, y++, 100, 220, 255); - drawText('Use createMaterialShader now.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(shaderObj ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md index 00adccf2..0c8d0353 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md +++ b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md @@ -37,54 +37,5 @@ The created framebuffer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const fb = t.createFramebuffer({ width: 24, height: 14 }); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - fb.begin(); - t.clear(); - t.background(20, 30, 60); - t.char('#'); - t.charColor(255, 210, 120); - t.rect(12, 4); - fb.end(); - t.image(fb); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CREATEFRAMEBUFFER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: OFFSCREEN BUFFER', x, y++, 100, 220, 255); - drawText('Renders into a framebuffer.', x, y++, 140, 160, 190); - drawText('Then draws it to the scene.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SIZE: ${fb.width} x ${fb.height}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md index a16c0f43..7bee4320 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md @@ -34,61 +34,5 @@ A TextmodeGlyphRamp instance. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const baseRamp = t.createGlyphRamp(' ░▒▓█'); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - - const ramp = baseRamp.shift(t.frameCount * 0.08); - for (let x = 0; x < t.grid.cols; x++) { - for (let y = 0; y < t.grid.rows; y++) { - const gx = x - Math.floor(t.grid.cols / 2); - const gy = y - Math.floor(t.grid.rows / 2); - const value = t.noise(x * 0.08, y * 0.12, t.secs * 0.3); - - t.push(); - t.translate(gx, gy); - t.charColor(80 + value * 140, 160 + value * 80, 230); - t.char(ramp.at(value)); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEGLYPHRAMP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH DENSITY RAMP', x, y++, 100, 220, 255); - drawText('Glyph strings create ramps.', x, y++, 140, 160, 190); - drawText('shift() cycles without mutating.', x, y++, 140, 160, 190); - drawText(`ramp: ${baseRamp.characters}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md index 8ae9d41b..d9d2951e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md @@ -39,80 +39,5 @@ A compiled shader ready for use with [shader](shader.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let materialShader = null; -let glyphA = [0, 0, 0]; -let glyphB = [0, 0, 0]; - -t.setup(async () => { - glyphA = t.font.characterMap.get('#')?.color ?? t.font.characters[1].color; - glyphB = t.font.characterMap.get('@')?.color ?? t.font.characters[2].color; - materialShader = await t.createMaterialShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -uniform vec3 u_glyphA; -uniform vec3 u_glyphB; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - float rings = sin((distance(v_uv, vec2(0.5)) - u_time) * 32.0); - float glyph = step(0.0, rings); - vec3 glyphId = mix(u_glyphA, u_glyphB, glyph); - vec3 primary = mix(vec3(0.2, 0.8, 1.0), vec3(1.0, 0.45, 0.25), glyph); - o_character = vec4(glyphId.xy, 0.0, 0.0); - o_primaryColor = vec4(primary, 1.0); - o_secondaryColor = vec4(0.01, 0.02, 0.05, 1.0); -}`); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(0); - if (!materialShader) return; - const time = t.frameCount * 0.003; - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - t.shader(materialShader); - t.setUniforms({ u_time: time, u_glyphA: glyphA, u_glyphB: glyphB }); - t.rotateY(t.frameCount); - t.sphere(8); - t.resetShader(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEMATERIALSHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GEOMETRY SHADER', x, y++, 100, 220, 255); - drawText('Fragment shader affects shapes.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(materialShader ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createShader.md b/api/textmode.js/classes/Textmodifier/methods/createShader.md index eac0f021..bd8671ae 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createShader.md @@ -35,69 +35,5 @@ The compiled shader. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let shaderObj; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_texCoord; - out vec2 v_uv; - void main(){gl_Position=a_position;v_uv=a_texCoord;}`; - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform float u_time; - layout(location=0) out vec4 o_character; - layout(location=1) out vec4 o_primaryColor; - layout(location=2) out vec4 o_secondaryColor; - void main(){float v=fract(v_uv.x*8.0+u_time);o_character=vec4(v,0,0,1);o_primaryColor=vec4(v,0.8,1.0,1);o_secondaryColor=vec4(0.02,0.04,0.08,1);}`; - shaderObj = await t.createShader(vert, frag); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (shaderObj) { - t.shader(shaderObj); - t.setUniform('u_time', t.frameCount * 0.02); - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CREATESHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); - drawText('Shader affects the main drawing.', x, y++, 140, 160, 190); - drawText('resetShader restores default.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(shaderObj ? 'SHADER: READY' : 'SHADER: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createTexture.md b/api/textmode.js/classes/Textmodifier/methods/createTexture.md index a3dd8c80..7489a406 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/createTexture.md @@ -39,59 +39,5 @@ A TextmodeTexture that can be drawn with [image](image.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const sourceCanvas = document.createElement('canvas'); -sourceCanvas.width = 64; -sourceCanvas.height = 64; -const ctx = sourceCanvas.getContext('2d'); -let texture; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - texture = t.createTexture(sourceCanvas); -}); - -t.draw(() => { - t.background(6, 10, 22); - ctx.fillStyle = '#10183a'; - ctx.fillRect(0, 0, 64, 64); - ctx.fillStyle = '#facc15'; - ctx.fillRect(8 + (t.frameCount % 32), 20, 16, 16); - if (texture) t.image(texture, 24, 14); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CREATETEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CANVAS TEXTURE', x, y++, 100, 220, 255); - drawText('Wraps a 2D canvas source.', x, y++, 140, 160, 190); - drawText('Source canvas is animated.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(texture ? 'TEXTURE: READY' : 'TEXTURE: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/createVector.md b/api/textmode.js/classes/Textmodifier/methods/createVector.md index 3fe0a7b1..655d8f95 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createVector.md +++ b/api/textmode.js/classes/Textmodifier/methods/createVector.md @@ -42,97 +42,5 @@ A new TextmodeVector instance. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const pos = t.createVector(-18, -6); -const vel = t.createVector(0.5, 0.12); -const acc = t.createVector(); -const target = t.createVector(); -const trail = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(point, char, r, g, b) { - t.push(); - t.translate(Math.round(point.x), Math.round(point.y)); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - - const time = t.frameCount * 0.045; - const radiusX = Math.max(8, t.grid.cols / 4); - const radiusY = Math.max(4, t.grid.rows / 4); - target.set(Math.cos(time) * radiusX, Math.sin(time * 0.8) * radiusY); - - const desired = target.copy().sub(pos); - const distance = desired.mag(); - const speed = t.map(Math.min(distance, 20), 0, 20, 0.08, 0.74); - const steer = desired.setMag(speed).sub(vel).limit(0.045); - - acc.set(steer); - vel.add(acc).limit(0.82); - pos.add(vel); - - trail.push(pos.copy()); - if (trail.length > 28) { - trail.shift(); - } - - for (let i = 0; i < trail.length; i++) { - const fade = i / trail.length; - const glyph = fade > 0.72 ? '*' : fade > 0.42 ? '+' : '.'; - plot(trail[i], glyph, 70 + fade * 120, 120 + fade * 120, 255); - } - - const ray = vel.copy().setMag(5); - for (let i = 1; i <= 5; i++) { - plot(pos.copy().add(ray.copy().setMag(i)), '-', 120, 255, 180); - } - - plot(target, 'x', 255, 120, 150); - plot(target.copy().add(0, -1), '|', 255, 80, 120); - plot(target.copy().add(-1, 0), '-', 255, 80, 120); - plot(target.copy().add(1, 0), '-', 255, 80, 120); - plot(pos, '@', 110, 255, 170); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CREATEVECTOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEKING MOTION', x, y++, 100, 220, 255); - drawText('target - position makes desired.', x, y++, 140, 160, 190); - drawText('setMag + limit shapes steering.', x, y++, 140, 160, 190); - drawText('velocity and position use add().', x, y++, 140, 160, 190); - drawText(`dist: ${pos.dist(target).toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`speed: ${vel.mag().toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`head: ${vel.heading().toFixed(0)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/cursor.md b/api/textmode.js/classes/Textmodifier/methods/cursor.md index a39dd6ed..460d0d66 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cursor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cursor.md @@ -38,101 +38,5 @@ See MDN for all options: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let currentCursor = 'default'; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(10, 12, 18); - const mx = t.mouse.x, - my = t.mouse.y; - const isInside = mx !== Number.NEGATIVE_INFINITY; - - if (isInside) { - if (mx < 0 && my < 0) currentCursor = 'crosshair'; - else if (mx >= 0 && my < 0) currentCursor = 'grab'; - else if (mx < 0 && my >= 0) currentCursor = 'not-allowed'; - else currentCursor = 'pointer'; - } else { - currentCursor = 'default'; - } - t.cursor(currentCursor); - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - for (let y = -hh + 1; y <= hh - 1; y += 1) { - for (let x = -hw + 1; x <= hw - 1; x += 1) { - const isTL = x < 0 && y < 0, - isTR = x >= 0 && y < 0; - const isBL = x < 0 && y >= 0, - isBR = x >= 0 && y >= 0; - const isActive = - isInside && - ((isTL && currentCursor === 'crosshair') || - (isTR && currentCursor === 'grab') || - (isBL && currentCursor === 'not-allowed') || - (isBR && currentCursor === 'pointer')); - - if (x === 0 || y === 0) { - t.push(); - t.translate(x, y); - t.charColor(40, 50, 75); - t.char(x === 0 && y === 0 ? '+' : x === 0 ? '|' : '-'); - t.point(); - t.pop(); - } else if (isActive) { - t.push(); - t.translate(x, y); - if (isTL) { - t.charColor(0, 229, 255); - t.cellColor(0, 40, 60); - t.char('+'); - } else if (isTR) { - t.charColor(0, 255, 136); - t.cellColor(0, 50, 30); - t.char('#'); - } else if (isBL) { - t.charColor(255, 51, 85); - t.cellColor(60, 0, 20); - t.char('X'); - } else { - t.charColor(255, 204, 0); - t.cellColor(60, 45, 0); - t.char('>'); - } - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.CURSOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DYNAMIC CURSOR SYNTHESIZER', x, y++, 100, 220, 255); - drawText('Updates cursor by hit-testing grid.', x, y++, 140, 160, 190); - drawText('Supports crosshair, grab & pointer.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ACTIVE CURSOR: ' + currentCursor.toUpperCase(), x, y++, 140, 255, 180); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/cylinder.md b/api/textmode.js/classes/Textmodifier/methods/cylinder.md index 9fb7d85e..ed72d96d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cylinder.md +++ b/api/textmode.js/classes/Textmodifier/methods/cylinder.md @@ -33,61 +33,5 @@ Draw a cylinder mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.cylinder(4, 12); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.CYLINDER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D CYLINDER', x, y++, 100, 220, 255); - drawText('Radius and height define form.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/degrees.md b/api/textmode.js/classes/Textmodifier/methods/degrees.md index ca8f4090..106c8750 100644 --- a/api/textmode.js/classes/Textmodifier/methods/degrees.md +++ b/api/textmode.js/classes/Textmodifier/methods/degrees.md @@ -34,82 +34,5 @@ Angle in degrees. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let angleDeg = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(6, 12, 18); - const targetX = t.mouse.x || Math.cos(t.frameCount * 0.025) * 10; - const targetY = t.mouse.y || Math.sin(t.frameCount * 0.025) * 6; - const radians = Math.atan2(targetY, targetX); - angleDeg = t.degrees(radians); - - t.char('.'); - t.charColor(42, 58, 86); - t.ellipse(14, 14); - t.line(-10, 0, 10, 0); - t.line(0, -6, 0, 6); - - t.char('+'); - t.charColor(90, 170, 230); - for (let i = 0; i < 12; i++) { - const a = (i / 12) * Math.PI * 2; - drawPoint(Math.cos(a) * 7, Math.sin(a) * 7); - } - - t.push(); - t.rotate(angleDeg); - t.char('>'); - t.charColor(255, 210, 110); - t.line(0, 0, 8, 0); - t.translate(9, 0); - t.point(); - t.pop(); - - t.char('o'); - t.charColor(120, 255, 180); - drawPoint(targetX, targetY); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DEGREES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RADIAN TO DEGREE', x, y++, 100, 220, 255); - drawText('atan2() gives radians.', x, y++, 140, 160, 190); - drawText('degrees() feeds rotate().', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ANGLE: ${angleDeg.toFixed(1)} DEG`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md index 8e75eb6a..a6411882 100644 --- a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md +++ b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md @@ -32,59 +32,5 @@ Milliseconds elapsed since the previous frame. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let xPos = -18; -let dt = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - dt = t.deltaTime(); - xPos += dt * 0.01; - if (xPos > 18) xPos = -18; - t.charColor(60, 70, 100); - t.char('-'); - t.line(-18, 0, 18, 0); - t.push(); - t.translate(xPos, 0); - t.char('@'); - t.charColor(140, 255, 180); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DELTATIME', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FRAME ELAPSED MS', x, y++, 100, 220, 255); - drawText('Motion scales by deltaTime.', x, y++, 140, 160, 190); - drawText('Speed stays frame-rate aware.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DT: ${dt.toFixed(1)} MS`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/destroy.md b/api/textmode.js/classes/Textmodifier/methods/destroy.md index 38ffdfce..a2f192e5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/destroy.md +++ b/api/textmode.js/classes/Textmodifier/methods/destroy.md @@ -28,54 +28,5 @@ After calling this method, the instance should not be used and will be eligible ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let requested = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - requested = true; -}); - -t.draw(() => { - t.background(12, 6, 8); - t.char(requested ? '!' : '#'); - t.charColor(requested ? 255 : 140, requested ? 120 : 220, 120); - t.rect(12, 5); - if (requested && t.frameCount % 120 === 0) t.destroy(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DESTROY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISPOSE INSTANCE', x, y++, 100, 220, 255); - drawText('Click requests cleanup.', x, y++, 140, 160, 190); - drawText('Destroy runs on next cycle.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(requested ? 'REQUESTED: YES' : 'REQUESTED: NO', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/dist.md b/api/textmode.js/classes/Textmodifier/methods/dist.md index b0d66757..bdb7918b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/dist.md +++ b/api/textmode.js/classes/Textmodifier/methods/dist.md @@ -41,78 +41,5 @@ The distance between the two points. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let distance = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(5, 10, 18); - const beaconX = Math.cos(t.frameCount * 0.025) * 8; - const beaconY = Math.sin(t.frameCount * 0.035) * 5; - distance = t.dist(beaconX, beaconY, t.mouse.x, t.mouse.y); - - for (let y = -10; y <= 10; y += 2) { - for (let x = -18; x <= 18; x += 2) { - const d = t.dist(x, y, beaconX, beaconY); - const shade = Math.round(t.constrain(t.map(d, 0, 20, 210, 35), 35, 210)); - t.char(d < 4 ? '*' : '.'); - t.charColor(60, shade, 255 - shade * 0.4); - drawPoint(x, y); - } - } - - t.char('o'); - t.charColor(255, 220, 120); - t.push(); - t.translate(beaconX, beaconY); - t.ellipse(8, 8); - t.point(); - t.pop(); - - t.char('+'); - t.charColor(120, 255, 180); - drawPoint(t.mouse.x, t.mouse.y); - t.line(beaconX, beaconY, t.mouse.x, t.mouse.y); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DIST', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POINT DISTANCE', x, y++, 100, 220, 255); - drawText('dist() measures between two points.', x, y++, 140, 160, 190); - drawText('Distance drives the field shading.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MOUSE RANGE: ${distance.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md index 88fdac90..44dea05a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md @@ -32,75 +32,5 @@ Register the single-callback handler for double-clicks. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.doubleClicked(() => { - addPulse('DOUBLE CLICK', t.mouse.x, t.mouse.y); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DOUBLECLICKED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DOUBLE CLICK', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('DOUBLE: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md index cdd75b5f..d1260599 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md @@ -35,76 +35,5 @@ helper lets you supply a dedicated handler when you want to treat double taps di ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.doubleTap((data) => { - const touch = data?.touch || t.mouse; - addPulse('DOUBLE', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DOUBLETAP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DOUBLE TAP', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('DOUBLE: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/draw.md b/api/textmode.js/classes/Textmodifier/methods/draw.md index 1ba9488e..61ff2992 100644 --- a/api/textmode.js/classes/Textmodifier/methods/draw.md +++ b/api/textmode.js/classes/Textmodifier/methods/draw.md @@ -42,53 +42,5 @@ textmodifier.layers.base.draw(callback); ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let pulse = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - pulse = 0.5 + 0.5 * Math.sin(t.frameCount * 0.05); - t.push(); - t.translate(8, 2); - t.char('#'); - t.charColor(120, 120 + pulse * 120, 255); - t.rect(6 + pulse * 8, 3 + pulse * 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DRAW', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FRAME CALLBACK', x, y++, 100, 220, 255); - drawText('draw() runs every frame.', x, y++, 140, 160, 190); - drawText('Pulse proves continuous updates.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`PULSE: ${pulse.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ease.md b/api/textmode.js/classes/Textmodifier/methods/ease.md index 18cb1283..08eaf542 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ease.md +++ b/api/textmode.js/classes/Textmodifier/methods/ease.md @@ -38,82 +38,5 @@ Eased amount. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const duration = 120; -const curves = [ - { name: 'linear', char: 'o', y: -6, color: [120, 190, 255] }, - { name: 'inQuad', char: 'q', y: -3, color: [255, 210, 120] }, - { name: 'outSine', char: 's', y: 0, color: [255, 140, 180] }, - { name: 'inOutCubic', char: '@', y: 3, color: [120, 255, 170] }, - { name: 'outBounce', char: 'b', y: 6, color: [190, 160, 255] }, -]; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function plot(x, y, char, r, g, b) { - t.push(); - t.translate(Math.round(x), y); - t.charColor(r, g, b); - t.char(char); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - - const amount = (t.frameCount % duration) / duration; - const labelWidth = 10; - const width = Math.max(8, Math.min(24, t.grid.cols - labelWidth - 10)); - const totalWidth = labelWidth + 2 + width; - const labelX = -Math.floor(totalWidth / 2); - const left = labelX + labelWidth + 2; - - for (const curve of curves) { - const eased = t.ease(curve.name, amount); - const x = t.lerp(left, left + width, eased); - const [r, g, b] = curve.color; - - drawText(curve.name, labelX, curve.y - 1, r, g, b); - - for (let step = 0; step <= width; step++) { - plot(left + step, curve.y, '-', 70, 95, 140); - } - - plot(x, curve.y, curve.char, r, g, b); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const amount = (t.frameCount % duration) / duration; - - drawText('TEXTMODIFIER.EASE', x, y++, 100, 255, 140); - drawText('----------------------', x, y++, 80, 100, 150); - drawText('CURVES IN MOTION', x, y++, 100, 220, 255); - drawText('same amount, different timing', x, y++, 140, 160, 190); - drawText(`amount: ${amount.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipse.md b/api/textmode.js/classes/Textmodifier/methods/ellipse.md index e77602f7..ae828663 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipse.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipse.md @@ -34,58 +34,5 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let rx = 0; -let ry = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - rx = 10 + Math.sin(time) * 4; - ry = 5 + Math.cos(time * 0.8) * 2; - t.push(); - t.translate(8, 1); - t.char('o'); - t.charColor(140, 220, 255); - t.cellColor(15, 25, 50); - t.ellipse(rx, ry); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ELLIPSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: OVAL PRIMITIVE', x, y++, 100, 220, 255); - drawText('Radius X and Y animate.', x, y++, 140, 160, 190); - drawText('The shape stays centered locally.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RX: ${rx.toFixed(1)}`, x, y++, 140, 255, 180); - drawText(`RY: ${ry.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md index 8a005333..4af57e96 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md @@ -37,61 +37,5 @@ Draw an ellipsoid mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.ellipsoid(8, 5, 6); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ELLIPSOID', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D ELLIPSOID', x, y++, 100, 220, 255); - drawText('Independent X, Y, Z radii.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/endShape.md b/api/textmode.js/classes/Textmodifier/methods/endShape.md index e822bdda..6f9cc4ba 100644 --- a/api/textmode.js/classes/Textmodifier/methods/endShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/endShape.md @@ -32,66 +32,5 @@ Finish the active custom shape and enqueue its geometry. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let points = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.025; - const spikes = 7; - const outer = 16 + Math.sin(time) * 2; - const inner = 6 + Math.cos(time * 1.4) * 1.5; - points = spikes * 2; - - t.push(); - t.rotateZ(time * 18); - t.char('*'); - t.charColor(255, 220, 96); - t.cellColor(24, 16, 4); - t.lineWeight(1.4); - t.beginShape(); - for (let i = 0; i < points; i++) { - const angle = t.radians(i * (360 / points) - 90); - const radius = i % 2 === 0 ? outer : inner; - t.vertex(Math.cos(angle) * radius, Math.sin(angle) * radius); - } - t.endShape('close'); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BEGINSHAPE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM 2D POLYGON', x, y++, 100, 220, 255); - drawText('Recorded vertices form one loop.', x, y++, 140, 160, 190); - drawText('Line state is captured per vertex.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VERTICES: ${points}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md index 26a010f6..1ec4775b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md @@ -26,97 +26,5 @@ Exit pointer lock if the textmode canvas currently owns it. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let rotX = 0, - rotY = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (document.pointerLockElement === t.canvas) t.exitPointerLock(); - else t.requestPointerLock(); -}); - -t.draw(() => { - t.background(5, 8, 10); - const isLocked = document.pointerLockElement === t.canvas; - - if (isLocked) { - rotX += t.movedX * 0.35; - rotY += t.movedY * 0.35; - } else { - rotX += 0.25; - } - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const rad = Math.floor(Math.min(hw, hh) * 0.65); - const angleOffset = (rotX * 0.05) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y * 1.4); - const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; - - let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; - let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); - let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; - - if (isRing || isAxis || isTick) { - t.push(); - t.translate(x, y); - - if (isLocked) { - if (d < 3) { - t.charColor(255, 51, 51); - t.cellColor(90, 0, 0); - t.char('+'); - } else if (isTick) { - t.charColor(255, 200, 0); - t.char('#'); - } else { - t.charColor(255, 153, 0); - t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); - } - } else { - t.charColor(68, 85, 102); - t.char(isAxis ? '+' : '.'); - } - - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isLocked = document.pointerLockElement === t.canvas; - - drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); - drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); - drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); - drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); - drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/exp.md b/api/textmode.js/classes/Textmodifier/methods/exp.md index 68a32e09..7891ce14 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exp.md +++ b/api/textmode.js/classes/Textmodifier/methods/exp.md @@ -34,68 +34,5 @@ Exponential value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let input = 0; -let output = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(8, 5, 15); - input = t.norm(t.sin(t.frameCount * 0.028) + t.cos(t.frameCount * 0.018) * 0.45, -1.45, 1.45) * 3 - 1.5; - output = t.exp(input); - - for (let i = 0; i <= 36; i++) { - const xValue = t.map(i, 0, 36, -1.5, 1.5); - const y = 8 - t.exp(xValue) * 2.2; - const heat = t.norm(xValue, -1.5, 1.5); - t.push(); - t.translate(-18 + i, y); - t.char(heat > 0.7 ? '#' : '+'); - t.charColor(100 + heat * 140, 120 + heat * 90, 230); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(255, 215, 100); - t.push(); - t.translate(t.map(input, -1.5, 1.5, -18, 18), 8 - output * 2.2); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.EXP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACCELERATING GROWTH', x, y++, 100, 220, 255); - drawText('exp(x) starts quiet, then blooms.', x, y++, 140, 160, 190); - drawText('The right side lifts rapidly.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INPUT: ${input.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`EXP: ${output.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/fill.md b/api/textmode.js/classes/Textmodifier/methods/fill.md index abbeb9a6..1de85fe5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fill.md +++ b/api/textmode.js/classes/Textmodifier/methods/fill.md @@ -30,54 +30,7 @@ Current cell color. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); - t.fill(red, 40, 120); - t.stroke(230, 245, 255); - t.char('.'); - t.rect(12, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); - drawText('Alias for cellColor.', x, y++, 140, 160, 190); - drawText('charColor controls the outline.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -100,54 +53,7 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); - t.fill(red, 40, 120); - t.stroke(230, 245, 255); - t.char('.'); - t.rect(12, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); - drawText('Alias for cellColor.', x, y++, 140, 160, 190); - drawText('charColor controls the outline.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -176,54 +82,7 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); - t.fill(red, 40, 120); - t.stroke(230, 245, 255); - t.char('.'); - t.rect(12, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); - drawText('Alias for cellColor.', x, y++, 140, 160, 190); - drawText('charColor controls the outline.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -245,51 +104,5 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(90 + 90 * Math.sin(t.frameCount * 0.04)); - t.fill(red, 40, 120); - t.stroke(230, 245, 255); - t.char('.'); - t.rect(12, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE INTERIOR', x, y++, 100, 220, 255); - drawText('Alias for cellColor.', x, y++, 140, 160, 190); - drawText('charColor controls the outline.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FILL R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/filter.md b/api/textmode.js/classes/Textmodifier/methods/filter.md index e1a2378d..1673ab3b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/filter.md +++ b/api/textmode.js/classes/Textmodifier/methods/filter.md @@ -45,51 +45,7 @@ queued per frame and will be applied in order. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(16, 8); - t.filter('invert', 0.5 + 0.5 * Math.sin(t.frameCount * 0.04)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILTER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POST FILTER', x, y++, 100, 220, 255); - drawText('Applies filter to final output.', x, y++, 140, 160, 190); - drawText('Invert amount animates.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FILTER: INVERT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -122,48 +78,5 @@ queued per frame and will be applied in order. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(16, 8); - t.filter('invert', 0.5 + 0.5 * Math.sin(t.frameCount * 0.04)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FILTER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POST FILTER', x, y++, 100, 220, 255); - drawText('Applies filter to final output.', x, y++, 140, 160, 190); - drawText('Invert amount animates.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FILTER: INVERT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/flipX.md b/api/textmode.js/classes/Textmodifier/methods/flipX.md index e8bcff24..1279b591 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipX.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipX.md @@ -34,60 +34,5 @@ Current flip state when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - for (let i = 0; i < 8; i++) { - const y = (i - 3.5) * 2; - t.push(); - t.translate(-6, y); - t.char('R'); - t.charColor(140, 220, 255); - t.point(); - t.pop(); - t.push(); - t.translate(8, y); - t.flipX(true); - t.char('R'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FLIPX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MIRROR GLYPH X', x, y++, 100, 220, 255); - drawText('Left column is normal.', x, y++, 140, 160, 190); - drawText('Right column is flipped.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FLIP X: ${t.flipX()}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/flipY.md b/api/textmode.js/classes/Textmodifier/methods/flipY.md index 5468778d..e88d6818 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipY.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipY.md @@ -34,60 +34,5 @@ Current flip state when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - for (let i = 0; i < 8; i++) { - const xPos = (i - 3.5) * 3; - t.push(); - t.translate(xPos, -3); - t.char('V'); - t.charColor(140, 220, 255); - t.point(); - t.pop(); - t.push(); - t.translate(xPos, 5); - t.flipY(true); - t.char('V'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FLIPY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MIRROR GLYPH Y', x, y++, 100, 220, 255); - drawText('Top row is normal.', x, y++, 140, 160, 190); - drawText('Bottom row is flipped.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FLIP Y: ${t.flipY()}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/floor.md b/api/textmode.js/classes/Textmodifier/methods/floor.md index a7539134..c0037cea 100644 --- a/api/textmode.js/classes/Textmodifier/methods/floor.md +++ b/api/textmode.js/classes/Textmodifier/methods/floor.md @@ -34,68 +34,5 @@ Largest integer less than or equal to the value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let snapped = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 8, 16); - raw = t.sin(t.frameCount * 0.035) * 11 + t.cos(t.frameCount * 0.023) * 3; - snapped = t.floor(raw); - - for (let x = -24; x <= 24; x++) { - t.char(x === snapped ? '#' : '.'); - t.charColor(x === snapped ? 255 : 55, x === snapped ? 220 : 70, 120); - t.push(); - t.translate(x, 0); - t.point(); - t.pop(); - } - - t.char('|'); - t.charColor(110, 220, 255); - t.line(snapped, -9, snapped, 9); - t.char('@'); - t.charColor(255, 140, 120); - t.push(); - t.translate(t.round(raw), -5); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FLOOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SNAP DOWN', x, y++, 100, 220, 255); - drawText('floor() chooses the lower cell.', x, y++, 140, 160, 190); - drawText('Red input becomes blue column.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`FLOOR: ${snapped}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/fontSize.md b/api/textmode.js/classes/Textmodifier/methods/fontSize.md index 0b4b5916..7868cca1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fontSize.md +++ b/api/textmode.js/classes/Textmodifier/methods/fontSize.md @@ -34,51 +34,5 @@ Current font size when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let size = 16; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - size = t.fontSize(); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FONTSIZE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACTIVE FONT SIZE', x, y++, 100, 220, 255); - drawText('Reads the current font size.', x, y++, 140, 160, 190); - drawText('Grid derives from cell size.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); - drawText(`COLS: ${t.grid.cols}`, x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/fract.md b/api/textmode.js/classes/Textmodifier/methods/fract.md index 9f486904..1eea4c8a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fract.md +++ b/api/textmode.js/classes/Textmodifier/methods/fract.md @@ -36,64 +36,5 @@ Fractional part in the range 0 up to, but not including, 1. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let fraction = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 17); - raw = t.frameCount * 0.035 + t.sin(t.frameCount * 0.021) * 0.5; - fraction = t.fract(raw); - - for (let x = -24; x <= 24; x++) { - const f = t.fract(raw + x * 0.18); - const y = 8 - f * 14; - t.push(); - t.translate(x, y); - t.char(f > 0.75 ? '#' : f > 0.35 ? '+' : '.'); - t.charColor(80 + f * 160, 135 + f * 100, 255); - t.point(); - t.pop(); - } - - t.char('|'); - t.charColor(255, 210, 100); - t.line(0, 8, 0, 8 - fraction * 14); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FRACT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: REPEATING DECIMALS', x, y++, 100, 220, 255); - drawText('fract(x) keeps the part after dot.', x, y++, 140, 160, 190); - drawText('The ramp resets at every integer.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`FRACT: ${fraction.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/frameRate.md b/api/textmode.js/classes/Textmodifier/methods/frameRate.md index 2c3b202d..a447a38f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/frameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/frameRate.md @@ -32,60 +32,5 @@ Set the target frame rate, or get the current measured frame rate when called wi ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let measured = 0; -let target = 60; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - target = Math.floor(t.frameCount / 180) % 2 === 0 ? 60 : 30; - t.frameRate(target); - measured = t.frameRate(); - const bars = Math.round(measured / 5); - for (let i = 0; i < bars; i++) { - t.push(); - t.translate(-18 + i, 3); - t.char('|'); - t.charColor(120, 220, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.FRAMERATE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FPS CONTROL', x, y++, 100, 220, 255); - drawText('Target alternates 60 and 30.', x, y++, 140, 160, 190); - drawText('Bars show measured rate.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TARGET: ${target}`, x, y++, 140, 255, 180); - drawText(`FPS: ${measured.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepad.md b/api/textmode.js/classes/Textmodifier/methods/gamepad.md index 0e006841..a84368c2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepad.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepad.md @@ -37,56 +37,5 @@ Returns `undefined` when that slot is currently absent or disconnected. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPAD', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const pad = t.gamepad(0); - const state = pad ? 'FOUND' : 'EMPTY'; - drawText(`SLOT 0: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md index 08f7bc9f..66dcf101 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md @@ -36,61 +36,5 @@ simpler choice; use this callback when you specifically want change notification ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let lastAxis = 'waiting'; - -t.gamepadAxisChanged((data) => { - const name = data.standardAxisName || 'axis ' + data.axisIndex; - lastAxis = name + ' ' + data.value.toFixed(2); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADAXISCHANGED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`AXIS: ${lastAxis}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md index 784757c5..dae1ece1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md @@ -34,60 +34,5 @@ This is a legacy-style single-callback shortcut for the `'gamepadButtonPressed'` ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let lastPress = 'waiting'; - -t.gamepadButtonPressed((data) => { - lastPress = data.standardButtonName || 'button ' + data.buttonIndex; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADBUTTONPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`PRESS: ${lastPress}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md index 19048fa0..61340f85 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md @@ -34,60 +34,5 @@ This is a legacy-style single-callback shortcut for the `'gamepadButtonReleased' ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let lastRelease = 'waiting'; - -t.gamepadButtonReleased((data) => { - lastRelease = data.standardButtonName || 'button ' + data.buttonIndex; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADBUTTONRELEASED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RELEASE: ${lastRelease}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md index 72bbb62f..d9465031 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md @@ -36,60 +36,5 @@ leaving any listeners added via [Textmodifier.on](on.md) untouched. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let lastConnect = 'waiting'; - -t.gamepadConnected((data) => { - lastConnect = 'slot ' + data.gamepad.index; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADCONNECTED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CONNECT: ${lastConnect}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md index 4517d5bb..b5039810 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md @@ -34,60 +34,5 @@ This is a legacy-style single-callback shortcut for the `'gamepadDisconnected'` ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let lastDisconnect = 'waiting'; - -t.gamepadDisconnected((data) => { - lastDisconnect = 'slot ' + data.gamepad.index; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADDISCONNECTED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DISCON: ${lastDisconnect}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/image.md b/api/textmode.js/classes/Textmodifier/methods/image.md index f8b3fa30..b28dac43 100644 --- a/api/textmode.js/classes/Textmodifier/methods/image.md +++ b/api/textmode.js/classes/Textmodifier/methods/image.md @@ -37,55 +37,5 @@ Draw a framebuffer, image, video, or texture source to the currently bound frame ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const fb = t.createFramebuffer({ width: 24, height: 14 }); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - fb.begin(); - t.clear(); - t.background(20, 30, 60); - t.rotateZ(t.frameCount * 2); - t.char('#'); - t.charColor(255, 210, 120); - t.rect(12, 4); - fb.end(); - t.image(fb, 24, 14); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.IMAGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DRAW IMAGE SOURCE', x, y++, 100, 220, 255); - drawText('Framebuffer is drawn as image.', x, y++, 140, 160, 190); - drawText('Offscreen content rotates.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('SOURCE: FRAMEBUFFER', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md index 23a9f3e6..e9d0812d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md +++ b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md @@ -40,70 +40,5 @@ When called without arguments, returns the current input grid mode:
## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const inputLayer = t.layers.add(); -let locked = false; -let mode = 'topmost'; - -t.setup(() => { - inputLayer.grid.cols = 24; - inputLayer.grid.rows = 12; -}); - -t.mouseClicked(() => { - locked = !locked; - t.inputGrid(locked ? inputLayer.grid : 'topmost'); - mode = locked ? 'locked' : 'topmost'; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.charColor(60, 80, 120); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); -}); - -inputLayer.draw(() => { - t.clear(); - t.charColor(100, 220, 255); - t.char('+'); - t.rect(inputLayer.grid.cols, inputLayer.grid.rows); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.INPUTGRID', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INPUT GRID LOCK', x, y++, 100, 220, 255); - drawText('Mouse mapping can lock.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${mode}`, x, y++, 140, 255, 180); - drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/invert.md b/api/textmode.js/classes/Textmodifier/methods/invert.md index de42038b..82834b33 100644 --- a/api/textmode.js/classes/Textmodifier/methods/invert.md +++ b/api/textmode.js/classes/Textmodifier/methods/invert.md @@ -34,64 +34,5 @@ Current inversion state when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(10, 12, 24); - - const count = 15; - for (let i = 0; i < count; i++) { - t.push(); - t.translate((i - (count - 1) / 2) * 5, 0); - - const shouldInvert = (i + Math.floor(t.frameCount / 25)) % 2 === 0; - t.invert(shouldInvert); - - t.charColor(255, 100, 100); - t.cellColor(0, 50, 100); - t.char('█'); - t.rect(4, 18); - t.pop(); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const invertActive = Math.floor(t.frameCount / 25) % 2 === 0; - - drawText('TEXTMODIFIER.INVERT', x, y++, 255, 100, 100); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CHROMA CHANNEL INVERSION', x, y++, 100, 220, 255); - drawText('Swaps char and cell colors.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = invertActive ? 'INVERTED' : 'STANDARD'; - drawText(`INVERT: ${state}`, x, y++, 120, 205, 255); - drawText('RECTS: 15', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('t.invert(shouldInvert)', x, y++, 100, 220, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md index 7d8878a1..5540a46b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md @@ -34,101 +34,5 @@ Check whether a key is currently pressed. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(), - flames = []; -let px = 0, - py = 0, - vx = 0, - vy = 0, - active = false; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 20); - const up = t.isKeyPressed('ArrowUp') || t.isKeyPressed('w') || t.isKeyPressed('W'); - const down = t.isKeyPressed('ArrowDown') || t.isKeyPressed('s') || t.isKeyPressed('S'); - const left = t.isKeyPressed('ArrowLeft') || t.isKeyPressed('a') || t.isKeyPressed('A'); - const right = t.isKeyPressed('ArrowRight') || t.isKeyPressed('d') || t.isKeyPressed('D'); - const boost = t.isKeyPressed(' '); - active = up || down || left || right || boost; - - if (up) vy -= 0.2; - if (down) vy += 0.2; - if (left) vx -= 0.2; - if (right) vx += 0.2; - if (boost) { - vx *= 1.05; - vy *= 1.05; - } - - if (active) flames.unshift({ x: px, y: py, vx: -vx * 0.5, vy: -vy * 0.5, life: 1 }); - if (flames.length > 40) flames.length = 40; - - vx *= 0.91; - vy *= 0.91; - px += vx; - py += vy; - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - px = Math.max(-hw + 5, Math.min(hw - 5, px)); - py = Math.max(-hh + 5, Math.min(hh - 5, py)); - - for (let i = flames.length - 1; i >= 0; i--) { - const f = flames[i]; - f.x += f.vx; - f.y += f.vy; - if ((f.life -= 0.04) <= 0) { - flames.splice(i, 1); - continue; - } - const fx = Math.round(f.x), - fy = Math.round(f.y); - if (fx >= -hw && fx <= hw && fy >= -hh && fy <= hh) { - t.push(); - t.translate(fx, fy); - t.charColor(255, f.life > 0.5 ? 170 : 80, 0); - if (f.life > 0.6) t.cellColor(90, 30, 0); - t.char(f.life > 0.7 ? '█' : f.life > 0.4 ? '▓' : '░'); - t.point(); - t.pop(); - } - } - - t.push(); - t.translate(Math.round(px), Math.round(py)); - t.charColor(0, boost ? 255 : 170, 255); - t.cellColor(0, 50, 90); - t.char(up ? '▲' : down ? '▼' : left ? '◄' : right ? '►' : '♦'); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.ISKEYPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SYNCHRONOUS KEY HOLD', x, y++, 100, 220, 255); - drawText('Evaluates held key state every frame.', x, y++, 140, 160, 190); - drawText('Use Arrows / WASD / Space to thrust.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('THRUSTERS: ' + (active ? 'ENGAGED' : 'IDLE'), x, y++, 140, 255, 180); - drawText('SPEED: ' + Math.hypot(vx, vy).toFixed(2), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/isLooping.md b/api/textmode.js/classes/Textmodifier/methods/isLooping.md index 4f20539f..7584d000 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isLooping.md +++ b/api/textmode.js/classes/Textmodifier/methods/isLooping.md @@ -28,59 +28,5 @@ Whether the automatic render loop is currently running. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.mousePressed(() => { - if (t.isLooping()) { - t.noLoop(); - t.redraw(); - } else { - t.loop(); - } -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char(t.isLooping() ? '>' : '|'); - t.charColor(t.isLooping() ? 100 : 255, 255, 140); - t.rotateZ(t.frameCount * 5); - t.rect(10, 10); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.ISLOOPING', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOOP STATE', x, y++, 100, 220, 255); - drawText('Compact API demonstration.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = t.isLooping() ? 'TRUE' : 'FALSE'; - drawText(`LOOPING: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK TO TOGGLE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md index 7d423f9e..6d7d838b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md @@ -32,99 +32,5 @@ Register the single-callback handler for key press events. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(), - rings = [], - bars = new Array(10).fill(0); -let keyCount = 0, - lastKey = 'NONE'; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.keyPressed((data) => { - keyCount++; - const k = data.key || 'KEY'; - lastKey = k; - rings.unshift({ age: 0, maxAge: 45, char: k.length === 1 ? k : '+' }); - bars[(k.length > 0 ? k.charCodeAt(0) : 0) % 10] = 1.0; - if (rings.length > 10) rings.length = 10; -}); - -t.draw(() => { - t.background(10, 5, 24); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - for (let i = rings.length - 1; i >= 0; i--) { - if (++rings[i].age >= rings[i].maxAge) rings.splice(i, 1); - } - - for (let i = 0; i < 10; i++) { - bars[i] *= 0.94; - const h = Math.floor(bars[i] * 12), - bx = (i - 4.5) * 4; - for (let dy = 0; dy < h; dy++) { - t.push(); - t.translate(Math.round(bx), hh - 4 - dy); - t.charColor(255, Math.floor(100 + dy * 12), Math.floor(dy * 20)); - if (dy > 8) t.cellColor(90, 0, 50); - t.char(dy === h - 1 ? '=' : '#'); - t.point(); - t.pop(); - } - } - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y); - let ringIntensity = 0, - ringChar = '+'; - for (let i = 0; i < rings.length; i++) { - const r = rings[i], - rad = r.age * 0.9, - dist = Math.abs(d - rad); - if (dist < 2.0) { - ringIntensity += (1 - dist / 2.0) * (1 - r.age / r.maxAge); - if (r.char.length === 1) ringChar = r.char; - } - } - if (ringIntensity > 0.15) { - t.push(); - t.translate(x, y); - t.charColor(0, 240, 255); - if (ringIntensity > 0.4) t.cellColor(0, 60, 90); - t.char(ringChar); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.KEYPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INITIAL KEY DOWN EVENT', x, y++, 100, 220, 255); - drawText('Fires on initial key down-stroke.', x, y++, 140, 160, 190); - drawText('Keypress ejects frequency shockwave.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('KEY PRESSES: ' + keyCount, x, y++, 140, 255, 180); - drawText('LAST KEY DOWN: ' + lastKey, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md index fc45b74c..8494a452 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md @@ -32,98 +32,5 @@ Register the single-callback handler for key release events. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(), - cascades = []; -let releaseCount = 0, - lastReleased = 'NONE'; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.keyReleased((data) => { - releaseCount++; - const k = data.key || 'KEY'; - lastReleased = k; - const ch = k.length === 1 ? k : '♦'; - - for (let i = 0; i < 18; i++) { - const a = (i / 18) * Math.PI * 2 + (Math.random() - 0.5) * 0.2; - const s = 0.5 + Math.random() * 1.1; - cascades.unshift({ x: 0, y: 0, vx: Math.cos(a) * s, vy: Math.sin(a) * s, life: 1.0, char: ch }); - } - if (cascades.length > 90) cascades.length = 90; -}); - -t.draw(() => { - t.background(6, 8, 16); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - // Central energy crystal - const tm = t.frameCount * 0.04; - const pulse = (Math.sin(tm) + 1) * 0.5; - t.push(); - t.translate(0, 0); - t.charColor(0, Math.floor(180 + pulse * 75), 255); - t.cellColor(0, 40, 80); - t.char('♦'); - t.point(); - t.pop(); - - // Dissipation particle cascades - for (let i = cascades.length - 1; i >= 0; i--) { - const c = cascades[i]; - c.x += c.vx; - c.y += c.vy; - c.vx *= 0.94; - c.vy *= 0.94; - if ((c.life -= 0.02) <= 0) { - cascades.splice(i, 1); - continue; - } - - const cx = Math.round(c.x), - cy = Math.round(c.y); - if (cx >= -hw && cx <= hw && cy >= -hh && cy <= hh) { - t.push(); - t.translate(cx, cy); - if (c.life > 0.6) { - t.charColor(255, 204, 0); - t.cellColor(70, 50, 0); - } else { - t.charColor(0, Math.floor(100 + c.life * 155), 200); - } - t.char(c.life > 0.7 ? c.char : c.life > 0.4 ? '∙' : '·'); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.KEYRELEASED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: UP-STROKE RELEASE CASCADE', x, y++, 100, 220, 255); - drawText('Fires on key release up-stroke.', x, y++, 140, 160, 190); - drawText('Key release dissipates energy cascades.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('KEY RELEASES: ' + releaseCount, x, y++, 140, 255, 180); - drawText('LAST RELEASED: ' + lastReleased, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md index e8939557..dfff2b7b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md @@ -35,93 +35,5 @@ punctuation, and space. It does not fire for modifier keys or control-key chords ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let buffer = 'TEXTMODE.JS', - typedCount = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -function getCardChar(cx, cy, w, h) { - if ((cy === 0 || cy === h - 1) && (cx === 0 || cx === w - 1)) return '+'; - return cy === 0 || cy === h - 1 ? '-' : '|'; -} - -t.keyTyped((data) => { - if (data.key && data.key.length === 1) { - typedCount++; - buffer = (buffer + data.key).slice(-28); - } -}); - -t.draw(() => { - t.background(4, 16, 8); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2), - tm = t.frameCount * 0.05; - - for (let y = -hh; y <= hh; y += 2) { - for (let x = -hw; x <= hw; x += 2) { - const rain = (Math.sin(x * 0.2 + tm + y * 0.1) + 1) * 0.5; - if (rain > 0.65) { - t.push(); - t.translate(x, y); - t.charColor(10, Math.floor(40 + rain * 60), 20); - t.char(String.fromCharCode(65 + ((x + y + Math.floor(tm)) % 26))); - t.point(); - t.pop(); - } - } - } - - const cardW = 32, - cardH = 5, - startX = -16, - startY = -2; - for (let cy = 0; cy < cardH; cy++) { - for (let cx = 0; cx < cardW; cx++) { - const isEdge = cx === 0 || cx === cardW - 1 || cy === 0 || cy === cardH - 1; - t.push(); - t.translate(startX + cx, startY + cy); - t.cellColor(2, 24, 12); - t.charColor(0, 180, 80); - t.char(isEdge ? getCardChar(cx, cy, cardW, cardH) : ' '); - t.point(); - t.pop(); - } - } - - t.push(); - t.printAlign('center', 'middle'); - t.charColor(0, 255, 102); - t.print(buffer + (Math.floor(t.frameCount / 20) % 2 === 0 ? '_' : ' '), 0, 0); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.KEYTYPED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PRINTABLE INPUT BUFFER', x, y++, 100, 220, 255); - drawText('Captures printable typed characters.', x, y++, 140, 160, 190); - drawText('Type any key to append to stream.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('TYPED CHARACTERS: ' + typedCount, x, y++, 140, 255, 180); - drawText('BUFFER LENGTH: ' + buffer.length, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/lerp.md b/api/textmode.js/classes/Textmodifier/methods/lerp.md index 7b73c84c..7809aa9b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lerp.md +++ b/api/textmode.js/classes/Textmodifier/methods/lerp.md @@ -39,84 +39,5 @@ The interpolated value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let blend = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(9, 10, 18); - blend = (Math.sin(t.frameCount * 0.035) + 1) * 0.5; - const left = -16; - const right = 16; - - t.char('-'); - t.charColor(55, 75, 115); - t.line(left, 0, right, 0); - - for (let i = 0; i <= 12; i++) { - const local = i / 12; - const x = t.lerp(left, right, local); - const y = Math.sin(local * Math.PI * 2 + t.frameCount * 0.04) * 5; - const r = Math.round(t.lerp(90, 255, local)); - const b = Math.round(t.lerp(255, 80, local)); - t.char(i % 2 === 0 ? '+' : '.'); - t.charColor(r, 160, b); - drawPoint(x, y); - } - - const x = t.lerp(left, right, blend); - const y = t.lerp(-7, 7, blend); - const size = Math.round(t.lerp(1, 4, blend)); - t.char('#'); - t.charColor(t.lerp(90, 255, blend), 230, t.lerp(255, 90, blend)); - t.rect(size, size); - - t.push(); - t.translate(x, y); - t.char('@'); - t.charColor(120, 255, 190); - t.rect(size + 1, size + 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LERP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INTERPOLATION', x, y++, 100, 220, 255); - drawText('lerp(a,b,t) blends between values.', x, y++, 140, 160, 190); - drawText('Position, color, and size all blend.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`T: ${blend.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md index 27021fef..44c55f0a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md +++ b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md @@ -40,56 +40,5 @@ Negative inputs are clamped to `0`. If all inputs resolve to `0`, the falloff re ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - value = 0.5 + 0.5 * Math.sin(time); - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - t.lightFalloff(1, value * 0.08, value * 0.01); - t.pointLight([255, 210, 120], { x: 18, y: -18, z: 28 }); - t.rotateY(time * 40); - t.char('#'); - t.charColor(140, 220, 255); - t.sphere(7); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LIGHTFALLOFF', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LIGHT FALLOFF', x, y++, 100, 220, 255); - drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); - drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FALLOFF: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/line.md b/api/textmode.js/classes/Textmodifier/methods/line.md index c4e9529f..555121b9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/line.md +++ b/api/textmode.js/classes/Textmodifier/methods/line.md @@ -39,60 +39,5 @@ Draw a line from `(x1, y1)` to `(x2, y2)`. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let a = 0; -let b = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.025; - a = Math.sin(time) * 10; - b = Math.cos(time * 0.7) * 7; - t.charColor(60, 70, 100); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - t.charColor(120, 220, 255); - t.char('#'); - t.line(-18, -b, 18, b); - t.charColor(255, 210, 120); - t.line(-a, -10, a, 10); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DRAW SEGMENTS', x, y++, 100, 220, 255); - drawText('Connects two grid coordinates.', x, y++, 140, 160, 190); - drawText('Animated endpoints cross center.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`A: ${a.toFixed(1)}`, x, y++, 140, 255, 180); - drawText(`B: ${b.toFixed(1)}`, x, y++, 255, 210, 120); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md index 83e2a84c..d101c55a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md +++ b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md @@ -34,56 +34,5 @@ Current line weight when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let weight = 1; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - weight = 1 + Math.floor((t.frameCount / 60) % 4); - t.charColor(70, 80, 110); - t.char('.'); - t.line(-20, -6, 20, -6); - t.line(-20, 6, 20, 6); - t.lineWeight(weight); - t.charColor(120, 255, 180); - t.char('#'); - t.line(-20, 0, 20, 0); - t.lineWeight(1); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINEWEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LINE THICKNESS', x, y++, 100, 220, 255); - drawText('Controls line cell thickness.', x, y++, 140, 160, 190); - drawText('Weight resets after the demo line.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`WEIGHT: ${weight}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/loadFont.md b/api/textmode.js/classes/Textmodifier/methods/loadFont.md index 946af3ec..36f7fc7e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadFont.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadFont.md @@ -44,89 +44,5 @@ The loaded TextmodeFont. ## Example -```javascript -const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const accentLayer = t.layers.add({ fontSize: 16, blendMode: 'additive' }); -const labelLayer = t.layers.add(); - -let baseFont = null; -let reusableFont = null; -let loaded = false; - -t.setup(async () => { - baseFont = await t.loadFont(BESCII_URL); - reusableFont = await t.loadFont(BESCII_URL, false); - await accentLayer.loadFont(reusableFont); - loaded = true; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawGlyphStrip(font, y, r, g, b) { - const glyphs = font.characters; - const count = Math.min(glyphs.length, Math.max(8, Math.floor(t.grid.cols * 0.55))); - const start = Math.floor((t.frameCount / 8) % glyphs.length); - const x = -Math.floor(count / 2); - for (let i = 0; i < count; i++) { - const glyph = glyphs[(start + i) % glyphs.length]; - t.push(); - t.translate(x + i, y); - t.char(glyph.character); - t.charColor(r, g, b); - t.point(); - t.pop(); - } -} - -t.draw(() => { - t.background(5, 8, 18); - if (!loaded) return; - - drawGlyphStrip(baseFont, -2, 255, 235, 120); - drawText('ACTIVE BASE FONT', -8, -5, 255, 235, 120); -}); - -accentLayer.draw(() => { - t.clear(); - if (!loaded) return; - - drawGlyphStrip(reusableFont, 4, 120, 220, 255); - drawText('REUSED ON LAYER', -7, 7, 120, 220, 255); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.LOADFONT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOAD WEB FONT', x, y++, 100, 220, 255); - drawText('true activates the base layer.', x, y++, 140, 160, 190); - drawText('false returns a reusable font.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = loaded ? 'READY' : 'LOADING'; - drawText(`FONT: ${state}`, x, y++, 140, 255, 180); - if (loaded) drawText(`GLYPHS: ${baseFont.characters.length}`, x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/loadImage.md b/api/textmode.js/classes/Textmodifier/methods/loadImage.md index e6bdba88..e61f5293 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadImage.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadImage.md @@ -34,52 +34,5 @@ The loaded TextmodeImage. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - source = await t.loadImage('https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&q=80'); - source.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(0); - if (source) t.image(source, t.grid.cols, t.grid.rows); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOADIMAGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOAD IMAGE', x, y++, 100, 220, 255); - drawText('Loads media for this example.', x, y++, 140, 160, 190); - drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(source ? 'IMAGE: READY' : 'IMAGE: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md index a141f72c..5bf3e163 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md @@ -44,65 +44,5 @@ The loaded TextmodeTileset. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - source = await t.loadTileset({ - source: 'https://littlebitspace.com/resources/fonts/T64.png', - columns: 16, - rows: 16, - count: 256, - }); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (source) { - for (let i = 0; i < 64; i++) { - t.push(); - t.translate((i % 16) - 8, Math.floor(i / 16)); - t.char(i); - t.charColor(120, 220, 255); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOADTILESET', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOAD TILESET', x, y++, 100, 220, 255); - drawText('Loads media for this example.', x, y++, 140, 160, 190); - drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(source ? 'TILESET: READY' : 'TILESET: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md index 78bdcf96..c37064d3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md @@ -32,52 +32,5 @@ Load a video source that can be drawn with [image](image.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - source = await t.loadVideo('https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'); - source.play(); -}); - -t.draw(() => { - t.background(0); - if (source) t.image(source, t.grid.cols, t.grid.rows); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOADVIDEO', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOAD VIDEO', x, y++, 100, 220, 255); - drawText('Loads media for this example.', x, y++, 140, 160, 190); - drawText('HUD stays on a top layer.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(source ? 'VIDEO: READY' : 'VIDEO: WAIT', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/log.md b/api/textmode.js/classes/Textmodifier/methods/log.md index 1c8cfbac..8aceb499 100644 --- a/api/textmode.js/classes/Textmodifier/methods/log.md +++ b/api/textmode.js/classes/Textmodifier/methods/log.md @@ -34,68 +34,5 @@ Natural logarithm. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let input = 1; -let output = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 8, 16); - input = 1 + t.norm(t.sin(t.frameCount * 0.03) + t.cos(t.frameCount * 0.019) * 0.4, -1.4, 1.4) * 24; - output = t.log(input); - - for (let i = 1; i <= 36; i++) { - const value = 1 + i * 0.7; - const y = 8 - t.log(value) * 4; - const glow = t.norm(value, 1, 26); - t.push(); - t.translate(-18 + i, y); - t.char(glow > 0.7 ? '#' : '+'); - t.charColor(90 + glow * 140, 155 + glow * 80, 255); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(255, 215, 100); - t.push(); - t.translate(t.map(input, 1, 26, -17, 18), 8 - output * 4); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOG', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: COMPRESSING GROWTH', x, y++, 100, 220, 255); - drawText('log(x) rises fast, then settles.', x, y++, 140, 160, 190); - drawText('Wide inputs fit a gentle curve.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INPUT: ${input.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`LOG: ${output.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/longPress.md b/api/textmode.js/classes/Textmodifier/methods/longPress.md index 45c7cd82..7c2b8b6c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/longPress.md +++ b/api/textmode.js/classes/Textmodifier/methods/longPress.md @@ -35,76 +35,5 @@ configured tolerance. The event includes the press duration in milliseconds. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.longPress((data) => { - const touch = data?.touch || t.mouse; - addPulse('LONG', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LONGPRESS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LONG PRESS', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('LONG: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/lookAt.md b/api/textmode.js/classes/Textmodifier/methods/lookAt.md index e9cac45a..8c5cfcbc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lookAt.md +++ b/api/textmode.js/classes/Textmodifier/methods/lookAt.md @@ -43,62 +43,5 @@ Update the look-at target and optional up vector for the active camera. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let targetX = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.03; - targetX = Math.sin(time) * 10; - t.perspective(58, 0.1, 4096); - t.camera(0, 0, 44); - t.lookAt(targetX, 0, 0); - t.ambientLight(20, 24, 34); - t.pointLight([255, 210, 140], { x: 16, y: -16, z: 28 }); - t.push(); - t.translate(targetX, 0, 0); - t.char('*'); - t.charColor(255, 220, 120); - t.box(4, 4, 4); - t.pop(); - t.char('#'); - t.charColor(120, 220, 255); - t.box(8, 8, 8); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOOKAT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: AIM CAMERA', x, y++, 100, 220, 255); - drawText('Camera eye remains fixed.', x, y++, 140, 160, 190); - drawText('Target slides across X.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TARGET X: ${targetX.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/loop.md b/api/textmode.js/classes/Textmodifier/methods/loop.md index 9366f27e..7306e74d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loop.md +++ b/api/textmode.js/classes/Textmodifier/methods/loop.md @@ -26,52 +26,5 @@ Resume the rendering loop if it was stopped by [noLoop](noLoop.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mousePressed(() => { - t.loop(); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.rotateZ(t.frameCount * 3); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(10, 2); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LOOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESUME DRAW LOOP', x, y++, 100, 220, 255); - drawText('Click calls loop().', x, y++, 140, 160, 190); - drawText('Spinner shows active frames.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CLICK: LOOP', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/map.md b/api/textmode.js/classes/Textmodifier/methods/map.md index 2f20e664..38136438 100644 --- a/api/textmode.js/classes/Textmodifier/methods/map.md +++ b/api/textmode.js/classes/Textmodifier/methods/map.md @@ -43,69 +43,5 @@ The remapped value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let mappedHeight = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 17); - const halfCols = Math.max(1, Math.floor(t.grid.cols / 2)); - const halfRows = Math.max(1, Math.floor(t.grid.rows / 2)); - const pointer = t.constrain(t.mouse.x, -halfCols, halfCols); - mappedHeight = t.map(pointer, -halfCols, halfCols, 1, 13); - - for (let i = 0; i < 17; i++) { - const x = -16 + i * 2; - const wave = Math.sin(t.frameCount * 0.04 + i * 0.55); - const height = Math.round(t.map(wave, -1, 1, 1, mappedHeight)); - const red = Math.round(t.map(i, 0, 16, 80, 255)); - const blue = Math.round(t.map(height, 1, 13, 255, 90)); - - t.char(i % 3 === 0 ? '#' : '|'); - t.charColor(red, 190, blue); - t.push(); - t.translate(x, 7 - height / 2); - t.rect(1, height); - t.pop(); - } - - const y = t.map(t.mouse.y, -halfRows, halfRows, -7, 7); - t.char('-'); - t.charColor(255, 230, 120); - t.line(-18, y, 18, y); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MAP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RANGE REMAPPING', x, y++, 100, 220, 255); - drawText('Mouse grid values become bar ranges.', x, y++, 140, 160, 190); - drawText('map() also colors each column.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`HEIGHT: ${mappedHeight.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/max.md b/api/textmode.js/classes/Textmodifier/methods/max.md index 989fd92a..f1b38436 100644 --- a/api/textmode.js/classes/Textmodifier/methods/max.md +++ b/api/textmode.js/classes/Textmodifier/methods/max.md @@ -36,68 +36,7 @@ Largest value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let high = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 6, 17); - const values = []; - for (let i = 0; i < 15; i++) { - values.push(t.round(t.cos(t.frameCount * 0.032 + i * 0.62) * 7 + t.sin(i * 0.8) * 3)); - } - high = t.max(values); - - for (let i = 0; i < values.length; i++) { - const x = -21 + i * 3; - const isHigh = values[i] === high; - t.push(); - t.translate(x, 6 - values[i] / 2); - t.char(isHigh ? '@' : '#'); - t.charColor(isHigh ? 120 : 80, isHigh ? 255 : 140, isHigh ? 170 : 230); - t.rect(1, t.abs(values[i]) + 1); - t.pop(); - } - - t.char('-'); - t.charColor(120, 245, 180); - t.line(-23, 6 - high, 23, 6 - high); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MAX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: UPPER ENVELOPE', x, y++, 100, 220, 255); - drawText('max(values...) finds the peak.', x, y++, 140, 160, 190); - drawText('The green line rides the crest.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MAX: ${high}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -121,65 +60,5 @@ Largest value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let high = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 6, 17); - const values = []; - for (let i = 0; i < 15; i++) { - values.push(t.round(t.cos(t.frameCount * 0.032 + i * 0.62) * 7 + t.sin(i * 0.8) * 3)); - } - high = t.max(values); - - for (let i = 0; i < values.length; i++) { - const x = -21 + i * 3; - const isHigh = values[i] === high; - t.push(); - t.translate(x, 6 - values[i] / 2); - t.char(isHigh ? '@' : '#'); - t.charColor(isHigh ? 120 : 80, isHigh ? 255 : 140, isHigh ? 170 : 230); - t.rect(1, t.abs(values[i]) + 1); - t.pop(); - } - - t.char('-'); - t.charColor(120, 245, 180); - t.line(-23, 6 - high, 23, 6 - high); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MAX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: UPPER ENVELOPE', x, y++, 100, 220, 255); - drawText('max(values...) finds the peak.', x, y++, 140, 160, 190); - drawText('The green line rides the crest.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MAX: ${high}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/min.md b/api/textmode.js/classes/Textmodifier/methods/min.md index 19bd43ff..c31bae0e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/min.md +++ b/api/textmode.js/classes/Textmodifier/methods/min.md @@ -36,68 +36,7 @@ Smallest value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let low = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 8, 17); - const values = []; - for (let i = 0; i < 15; i++) { - values.push(t.round(t.sin(t.frameCount * 0.035 + i * 0.7) * 7 + t.cos(i) * 3)); - } - low = t.min(values); - - for (let i = 0; i < values.length; i++) { - const x = -21 + i * 3; - const isLow = values[i] === low; - t.push(); - t.translate(x, 6 - values[i] / 2); - t.char(isLow ? '@' : '#'); - t.charColor(isLow ? 255 : 80, isLow ? 215 : 140, isLow ? 110 : 230); - t.rect(1, t.abs(values[i]) + 1); - t.pop(); - } - - t.char('-'); - t.charColor(255, 160, 110); - t.line(-23, 6 - low, 23, 6 - low); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MIN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOWER ENVELOPE', x, y++, 100, 220, 255); - drawText('min(array) finds the lowest bar.', x, y++, 140, 160, 190); - drawText('The orange line follows it.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MIN: ${low}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -121,65 +60,5 @@ Smallest value. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let low = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 8, 17); - const values = []; - for (let i = 0; i < 15; i++) { - values.push(t.round(t.sin(t.frameCount * 0.035 + i * 0.7) * 7 + t.cos(i) * 3)); - } - low = t.min(values); - - for (let i = 0; i < values.length; i++) { - const x = -21 + i * 3; - const isLow = values[i] === low; - t.push(); - t.translate(x, 6 - values[i] / 2); - t.char(isLow ? '@' : '#'); - t.charColor(isLow ? 255 : 80, isLow ? 215 : 140, isLow ? 110 : 230); - t.rect(1, t.abs(values[i]) + 1); - t.pop(); - } - - t.char('-'); - t.charColor(255, 160, 110); - t.line(-23, 6 - low, 23, 6 - low); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MIN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOWER ENVELOPE', x, y++, 100, 220, 255); - drawText('min(array) finds the lowest bar.', x, y++, 140, 160, 190); - drawText('The orange line follows it.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MIN: ${low}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md index e0c51dac..05bb98ff 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md @@ -32,87 +32,5 @@ Register the single-callback handler for mouse clicks. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const RAMP = ' .:=+*#%@'; -const labelLayer = t.layers.add(); -const ripples = []; -let clickCount = 0; -let lastPos = 'NONE'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (t.mouse.x !== Number.NEGATIVE_INFINITY) { - clickCount++; - lastPos = `(${t.mouse.x}, ${t.mouse.y})`; - ripples.unshift({ x: t.mouse.x, y: t.mouse.y, age: 0, maxAge: 60 }); - if (ripples.length > 12) ripples.length = 12; - } -}); - -t.draw(() => { - t.background(10, 8, 24); - for (let i = ripples.length - 1; i >= 0; i--) { - if (++ripples[i].age >= ripples[i].maxAge) ripples.splice(i, 1); - } - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2), - tm = t.frameCount * 0.04; - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const ambient = (Math.sin(x * 0.15 + tm) * Math.cos(y * 0.15 - tm * 0.8) + 1) * 0.2; - let rippleVal = 0; - for (let i = 0; i < ripples.length; i++) { - const rip = ripples[i], - d = Math.hypot(x - rip.x, y - rip.y), - rad = rip.age * 0.75; - const dist = Math.abs(d - rad); - if (dist < 3.5) rippleVal += Math.cos((dist / 3.5) * Math.PI * 0.5) * (1 - rip.age / rip.maxAge); - } - const val = Math.min(1, ambient + rippleVal); - if (val > 0.08) { - const charIdx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); - t.push(); - t.translate(x, y); - if (rippleVal > 0.3) { - const g = Math.min(1, (rippleVal - 0.3) / 0.7); - t.charColor(Math.floor(220 + g * 35), Math.floor(170 + g * 85), Math.floor(51 + g * 204)); - t.cellColor(Math.floor(40 * g), Math.floor(20 * g), Math.floor(60 * g)); - } else { - const b = val / 0.5; - t.charColor(Math.floor(26 + b * 20), Math.floor(58 + b * 50), Math.floor(75 + b * 60)); - } - t.char(RAMP[charIdx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSECLICKED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISCRETE CLICK EVENT', x, y++, 100, 220, 255); - drawText('Fires once per press & release.', x, y++, 140, 160, 190); - drawText('Clicking injects wave discharge.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('TOTAL CLICKS: ' + clickCount, x, y++, 140, 255, 180); - drawText('LAST CLICK: ' + lastPos, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md index 189def06..ec234e6d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md @@ -32,94 +32,5 @@ Register the single-callback handler for mouse dragging. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -const particles = []; -let dragCount = 0; -let isDragging = false; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseDragged(() => { - if (t.mouse.x === Number.NEGATIVE_INFINITY) return; - isDragging = true; - dragCount++; - const vx = (t.mouse.x - t.pmouse.x) * 0.3; - const vy = (t.mouse.y - t.pmouse.y) * 0.3; - particles.unshift({ x: t.mouse.x, y: t.mouse.y, vx, vy, life: 1 }); - if (particles.length > 80) particles.length = 80; -}); - -t.draw(() => { - t.background(8, 12, 20); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.02; - - for (let y = -hh; y <= hh; y += 3) { - for (let x = -hw; x <= hw; x += 3) { - const a = Math.sin(x * 0.08 + tm) + Math.cos(y * 0.08 - tm * 0.8); - t.push(); - t.translate(x, y); - t.charColor(14, 56, 43); - t.char(a > 1.0 ? '/' : a > 0.2 ? '|' : a > -0.8 ? '\\' : '-'); - t.point(); - t.pop(); - } - } - - for (let i = particles.length - 1; i >= 0; i--) { - const p = particles[i]; - p.x += p.vx; - p.y += p.vy; - p.vx *= 0.94; - p.vy *= 0.94; - const a = Math.sin(p.x * 0.08 + tm) + Math.cos(p.y * 0.08 - tm * 0.8); - p.vx += Math.cos(a) * 0.05; - p.vy += Math.sin(a) * 0.05; - if ((p.life -= 0.02) <= 0) { - particles.splice(i, 1); - continue; - } - const px = Math.round(p.x); - const py = Math.round(p.y); - if (px >= -hw && px <= hw && py >= -hh && py <= hh) { - t.push(); - t.translate(px, py); - t.charColor(p.life > 0.6 ? 163 : 57, p.life > 0.6 ? 255 : p.life > 0.3 ? 255 : 90, p.life > 0.6 ? 206 : 20); - if (p.life > 0.3) t.cellColor(p.life > 0.6 ? 20 : 10, p.life > 0.6 ? 80 : 40, p.life > 0.6 ? 50 : 25); - t.char(p.life > 0.6 ? '█' : p.life > 0.3 ? '▓' : '░'); - t.point(); - t.pop(); - } - } - if (!t.mouseIsPressed) isDragging = false; -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSEDRAGGED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONTINUOUS DRAG EVENT', x, y++, 100, 220, 255); - drawText('Fires continuously while dragging.', x, y++, 140, 160, 190); - drawText('Injects fluid particle streamlines.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('DRAG EVENTS: ' + dragCount, x, y++, 140, 255, 180); - drawText('DRAGGING: ' + (isDragging ? 'TRUE' : 'FALSE'), x, y++, 180, 200, 220); - drawText('PARTICLES: ' + particles.length, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md index 1f0e40bd..44b5d452 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md @@ -32,90 +32,5 @@ Register the single-callback handler for mouse movement. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const RAMP = ' .:;ilwW@'; -const labelLayer = t.layers.add(); -const moveHistory = []; -let moveCount = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseMoved(() => { - if (t.mouse.x !== Number.NEGATIVE_INFINITY) { - moveCount++; - moveHistory.unshift({ x: t.mouse.x, y: t.mouse.y, life: 1.0 }); - if (moveHistory.length > 20) moveHistory.length = 20; - } -}); - -t.draw(() => { - t.background(2, 11, 8); - for (let i = moveHistory.length - 1; i >= 0; i--) { - if ((moveHistory[i].life -= 0.025) <= 0) moveHistory.splice(i, 1); - } - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const sweepAngle = (t.frameCount * 0.04) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const elevation = (Math.sin(x * 0.1 + y * 0.05) + Math.cos(x * 0.05 - y * 0.1) + 2) * 0.25; - let angleDiff = Math.abs(Math.atan2(y, x) + Math.PI - sweepAngle); - if (angleDiff > Math.PI) angleDiff = Math.PI * 2 - angleDiff; - const sweepVal = angleDiff < 0.15 ? (1 - angleDiff / 0.15) * 0.6 : 0; - - let maxHeat = 0; - for (let i = 0; i < moveHistory.length; i++) { - const n = moveHistory[i], - d = Math.hypot(x - n.x, y - n.y); - if (d < 12) maxHeat = Math.max(maxHeat, (1 - d / 12) * n.life); - } - - const val = Math.min(1, elevation * 0.35 + sweepVal + maxHeat * 0.85); - if (val > 0.08) { - const charIdx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); - t.push(); - t.translate(x, y); - if (maxHeat > 0.4) { - t.charColor(204, 255, 0); - t.cellColor(20, 45, 10); - } else if (sweepVal > 0.2) { - t.charColor(0, 229, 255); - } else { - const b = val; - t.charColor(Math.floor(8 + b * 20), Math.floor(36 + b * 90), Math.floor(27 + b * 70)); - } - t.char(RAMP[charIdx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSEMOVED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PASSIVE MOVEMENT EVENT', x, y++, 100, 220, 255); - drawText('Fires on hover without clicking.', x, y++, 140, 160, 190); - drawText('Hovering leaves phosphor sonar trails.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('MOVE EVENTS: ' + moveCount, x, y++, 140, 255, 180); - drawText('TRAIL NODES: ' + moveHistory.length, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md index a12063bf..c3f50f87 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md @@ -32,89 +32,5 @@ Register the single-callback handler for mouse press events. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -const shocks = []; -let pressCount = 0, - lastDown = 'NONE'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mousePressed(() => { - if (t.mouse.x !== Number.NEGATIVE_INFINITY) { - pressCount++; - lastDown = `(${t.mouse.x}, ${t.mouse.y})`; - shocks.unshift({ x: t.mouse.x, y: t.mouse.y, age: 0, maxAge: 40 }); - if (shocks.length > 10) shocks.length = 10; - } -}); - -t.draw(() => { - t.background(18, 18, 20); - for (let i = shocks.length - 1; i >= 0; i--) { - if (++shocks[i].age >= shocks[i].maxAge) shocks.splice(i, 1); - } - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const isDiag1 = (x + y) % 7 === 0, - isDiag2 = (x - y) % 7 === 0; - const symbol = isDiag1 && isDiag2 ? '+' : isDiag1 ? '/' : isDiag2 ? '\\' : ' '; - - let shockIntensity = 0; - for (let i = 0; i < shocks.length; i++) { - const s = shocks[i], - dist = Math.abs(Math.hypot(x - s.x, y - s.y) - s.age * 1.2); - if (dist < 2.5) shockIntensity += (1 - dist / 2.5) * (1 - s.age / s.maxAge); - } - - if (symbol !== ' ' || shockIntensity > 0.1) { - t.push(); - t.translate(x, y); - if (shockIntensity > 0.4) { - t.charColor(255, 255, 255); - t.cellColor(255, 0, 85); - t.char(symbol === ' ' ? '#' : '+'); - } else if (shockIntensity > 0.15) { - t.charColor(255, 107, 107); - t.cellColor(70, 0, 30); - t.char(symbol === ' ' ? '=' : symbol); - } else { - t.charColor(42, 46, 61); - t.char(symbol); - } - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSEPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DOWN-STROKE PRESS EVENT', x, y++, 100, 220, 255); - drawText('Fires on initial down-stroke.', x, y++, 140, 160, 190); - drawText('Down-stroke fractures truss lines.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('DOWN PRESSES: ' + pressCount, x, y++, 140, 255, 180); - drawText('LAST DOWN: ' + lastDown, x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md index dbbebf5e..a41a79eb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md @@ -32,101 +32,5 @@ Register the single-callback handler for mouse release events. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -const sparks = []; -let tension = 0, - releaseCount = 0, - lastPos = 'NONE'; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseReleased(() => { - if (t.mouse.x === Number.NEGATIVE_INFINITY) return; - releaseCount++; - lastPos = `(${t.mouse.x}, ${t.mouse.y})`; - for (let i = 0; i < 14; i++) { - const a = (i / 14) * Math.PI * 2, - s = (0.8 + Math.random()) * (0.4 + tension * 0.8); - sparks.unshift({ x: t.mouse.x, y: t.mouse.y, vx: Math.cos(a) * s, vy: Math.sin(a) * s, life: 1 }); - } - tension = 0; - if (sparks.length > 70) sparks.length = 70; -}); - -t.draw(() => { - t.background(8, 8, 16); - const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; - tension = isHeld ? Math.min(1, tension + 0.04) : Math.max(0, tension - 0.08); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - for (let y = -hh; y <= hh; y += 2) { - for (let x = -hw; x <= hw; x += 2) { - const d = isHeld ? Math.hypot(x - t.mouse.x, y - t.mouse.y) : 999; - const pull = d < 20 ? (1 - d / 20) * tension * 3 : 0; - const rx = Math.round(x + (isHeld ? (t.mouse.x - x) * (pull / (d + 1)) : 0)); - const ry = Math.round(y + (isHeld ? (t.mouse.y - y) * (pull / (d + 1)) : 0)); - if (rx >= -hw && rx <= hw && ry >= -hh && ry <= hh) { - t.push(); - t.translate(rx, ry); - t.charColor(pull > 0.4 ? 255 : 30, pull > 0.4 ? Math.floor(100 + pull * 155) : 40, pull > 0.4 ? 0 : 70); - if (pull > 0.4) t.cellColor(80, 20, 0); - t.char(pull > 0.4 ? '#' : '+'); - t.point(); - t.pop(); - } - } - } - - for (let i = sparks.length - 1; i >= 0; i--) { - const s = sparks[i]; - s.x += s.vx; - s.y += s.vy; - s.vx *= 0.93; - s.vy *= 0.93; - if ((s.life -= 0.025) <= 0) { - sparks.splice(i, 1); - continue; - } - const sx = Math.round(s.x), - sy = Math.round(s.y); - if (sx >= -hw && sx <= hw && sy >= -hh && sy <= hh) { - t.push(); - t.translate(sx, sy); - t.charColor(s.life > 0.6 ? 255 : 0, s.life > 0.6 ? 255 : 235, 255); - if (s.life > 0.5) t.cellColor(0, 70, 90); - t.char(s.life > 0.7 ? '@' : s.life > 0.4 ? 'O' : '*'); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSERELEASED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: UP-STROKE RELEASE EVENT', x, y++, 100, 220, 255); - drawText('Fires on mouse button release.', x, y++, 140, 160, 190); - drawText('Releasing launches kinetic spark burst.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('TOTAL RELEASES: ' + releaseCount, x, y++, 140, 255, 180); - drawText('LAST RELEASE: ' + lastPos, x, y++, 180, 200, 220); - drawText('TENSION CHARGE: ' + Math.floor(tension * 100) + '%', x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md index 5db1e0ce..aaef85bd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md @@ -32,89 +32,5 @@ Register the single-callback handler for mouse wheel scrolling. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const RAMP = '·:;oO8@█'; -const labelLayer = t.layers.add(); -let scrollDepth = 0, - lastDelta = 0, - scrollCount = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseScrolled((data) => { - lastDelta = data.delta.y; - scrollDepth += data.delta.y * 0.04; - scrollCount++; -}); - -t.draw(() => { - t.background(4, 4, 8); - scrollDepth += 0.012; // Baseline ambient tunnel movement - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const dist = Math.hypot(x, y * 1.3); - let ringPhase = (dist * 0.2 - scrollDepth) % 1.0; - if (ringPhase < 0) ringPhase += 1.0; - - if (ringPhase < 0.4) { - const intensity = 1 - ringPhase / 0.4; - const charIdx = Math.min(RAMP.length - 1, Math.floor(intensity * RAMP.length)); - t.push(); - t.translate(x, y); - - if (dist < 6) { - // Golden Electric center core - t.charColor(255, Math.floor(200 + intensity * 55), 0); - t.cellColor(90, 40, 0); - } else if (dist < 18) { - // Neon Magenta middle tunnel - t.charColor(255, 0, Math.floor(127 + intensity * 128)); - t.cellColor(60, 0, 30); - } else { - // Deep Violet outer rings - t.charColor( - Math.floor(58 + intensity * 80), - Math.floor(28 + intensity * 50), - Math.floor(94 + intensity * 100) - ); - } - - t.char(RAMP[charIdx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSESCROLLED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCROLL DELTA & DEPTH ZOOM', x, y++, 100, 220, 255); - drawText('Fires on mouse wheel or touchpad scroll.', x, y++, 140, 160, 190); - drawText('Scrolling steps depth through tunnel.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('SCROLL EVENTS: ' + scrollCount, x, y++, 140, 255, 180); - drawText('DEPTH POSITION: ' + scrollDepth.toFixed(2), x, y++, 180, 200, 220); - drawText('LAST SCROLL DELTA: ' + lastDelta.toFixed(1), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noLights.md b/api/textmode.js/classes/Textmodifier/methods/noLights.md index 7785ed91..c6b935b4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLights.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLights.md @@ -28,56 +28,5 @@ Useful when you want later draw calls in the same frame to render unlit. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - value = 0.5 + 0.5 * Math.sin(time); - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - if (value > 0.5) t.noLights(); - else t.pointLight([255, 210, 120], { x: 18, y: -18, z: 28 }); - t.rotateY(time * 40); - t.char('#'); - t.charColor(140, 220, 255); - t.sphere(7); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.NOLIGHTS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISABLE LIGHTS', x, y++, 100, 220, 255); - drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); - drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(value > 0.5 ? 'LIGHTS: OFF' : 'LIGHTS: ON', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noLoop.md b/api/textmode.js/classes/Textmodifier/methods/noLoop.md index 7938122f..876feffd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLoop.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLoop.md @@ -28,62 +28,5 @@ Rendering can be resumed later with [loop](loop.md). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let paused = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mousePressed(() => { - if (t.isLooping()) { - paused = true; - t.noLoop(); - t.redraw(); - } else { - paused = false; - t.loop(); - } -}); - -t.draw(() => { - t.background(6, 10, 22); - t.rotateZ(t.frameCount * 4); - t.char('#'); - t.charColor(255, 210, 120); - t.rect(12, 2); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.NOLOOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PAUSE DRAW LOOP', x, y++, 100, 220, 255); - drawText('Click toggles noLoop/loop.', x, y++, 140, 160, 190); - drawText('Events still resume drawing.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = paused ? 'PAUSED' : 'LOOPING'; - drawText(`STATE: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK: TOGGLE LOOP', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noTexture.md b/api/textmode.js/classes/Textmodifier/methods/noTexture.md index a674e29d..630e394b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/noTexture.md @@ -26,91 +26,5 @@ Clear the active texture for later geometry draws. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const sourceCanvas = document.createElement('canvas'); -sourceCanvas.width = 96; -sourceCanvas.height = 96; -const ctx = sourceCanvas.getContext('2d'); -let source; -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - source = t.createTexture(sourceCanvas); - source.characters(' .:-=+*#%@').cellColorMode('fixed').cellColor(5, 9, 18); -}); - -t.draw(() => { - t.background(5, 9, 20); - if (!ctx || !source) return; - - const hue = (t.frameCount * 2.5) % 360; - const gradient = ctx.createRadialGradient(48, 48, 10, 48, 48, 48); - gradient.addColorStop(0, '#f8fafc'); - gradient.addColorStop(0.45, `hsl(${hue}, 92%, 58%)`); - gradient.addColorStop(1, `hsl(${(hue + 170) % 360}, 88%, 34%)`); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 96); - ctx.fillStyle = '#111827'; - ctx.fillRect(28, 28, 40, 40); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(38, 38, 20, 20); - - spin = (t.frameCount * 1.4) % 360; - t.perspective(58, 0.1, 4096); - t.camera(0, -8, 38, 0, 0, 0); - t.ambientLight(20, 22, 30); - t.pointLight([255, 235, 180], { x: 18, y: -18, z: 30 }); - t.push(); - t.translate(-10, 0, 0); - t.rotateY(spin); - t.rotateX(14); - t.texture(source); - t.sphere(8); - t.pop(); - t.noTexture(); - t.push(); - t.translate(10, 0, 0); - t.rotateY(spin); - t.rotateX(14); - t.char('@'); - t.charColor(245, 245, 210); - t.cellColor(20, 28, 48); - t.sphere(8); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.NOTEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLEAR TEXTURE', x, y++, 100, 220, 255); - drawText('Left sphere samples the source.', x, y++, 140, 160, 190); - drawText('Right sphere ignores it after clear.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noise.md b/api/textmode.js/classes/Textmodifier/methods/noise.md index 39b6f8c3..4db20f4a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noise.md +++ b/api/textmode.js/classes/Textmodifier/methods/noise.md @@ -42,61 +42,5 @@ Noise value in the range `[0, 1]`. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'noise-field', -}); - -const labelLayer = t.layers.add(); -const ramp = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(3, 8, 18); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - const time = t.frameCount * 0.018; - - for (let y = 0; y < t.grid.rows; y += 1) { - for (let x = 0; x < t.grid.cols; x += 1) { - const value = t.noise(x * 0.08, y * 0.08, time); - const index = Math.floor(value * (ramp.length - 1)); - t.push(); - t.translate(left + x, top + y); - t.char(ramp[index]); - t.charColor(60 + value * 180, 150 + value * 90, 255); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.NOISE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORGANIC FIELD', x, y++, 100, 220, 255); - drawText('Nearby inputs return close values.', x, y++, 140, 160, 190); - drawText('Z acts like a smooth time axis.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md index be0f07ad..92daf013 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md @@ -36,64 +36,5 @@ contributes compared to the previous one. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'noise-detail', -}); - -const labelLayer = t.layers.add(); -const ramp = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPanel(offsetX, octaves, falloff) { - const top = -Math.floor(t.grid.rows / 2) + 11; - t.noiseDetail(octaves, falloff); - for (let y = 0; y < Math.min(16, t.grid.rows - 13); y += 1) { - for (let x = 0; x < 20; x += 1) { - const value = t.noise(x * 0.14, y * 0.14, t.frameCount * 0.012); - const index = Math.floor(value * (ramp.length - 1)); - t.push(); - t.translate(offsetX + x, top + y); - t.char(ramp[index]); - t.charColor(90 + value * 150, 140 + value * 100, 255); - t.point(); - t.pop(); - } - } -} - -t.draw(() => { - t.background(5, 8, 18); - drawPanel(-24, 2, 0.35); - drawPanel(4, 7, 0.65); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.NOISEDETAIL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: OCTAVES + FALLOFF', x, y++, 100, 220, 255); - drawText('Left: soft, low detail.', x, y++, 140, 160, 190); - drawText('Right: richer fine texture.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md index 820a996a..c1ce4575 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md @@ -35,63 +35,5 @@ current random sequence. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const ramp = ' .:-=+*#%@'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawBand(offsetX) { - const top = -Math.floor(t.grid.rows / 2) + 10; - t.noiseSeed('matched-band'); - for (let y = 0; y < Math.min(18, t.grid.rows - 12); y += 1) { - for (let x = 0; x < 18; x += 1) { - const value = t.noise(x * 0.12, y * 0.12, t.frameCount * 0.01); - const index = Math.floor(value * (ramp.length - 1)); - t.push(); - t.translate(offsetX + x, top + y); - t.char(ramp[index]); - t.charColor(80 + value * 160, 255, 130 + value * 100); - t.point(); - t.pop(); - } - } -} - -t.draw(() => { - t.background(5, 10, 18); - drawBand(-22); - drawBand(4); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.NOISESEED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: REPEATABLE FIELDS', x, y++, 100, 220, 255); - drawText('Both bands use the same seed.', x, y++, 140, 160, 190); - drawText('Same coordinates make same values.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/norm.md b/api/textmode.js/classes/Textmodifier/methods/norm.md index af862986..81217f9e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/norm.md +++ b/api/textmode.js/classes/Textmodifier/methods/norm.md @@ -41,67 +41,5 @@ The normalized value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let normalized = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 7, 17); - const low = -18; - const high = 18; - raw = t.sin(t.frameCount * 0.04) * 20 + t.cos(t.frameCount * 0.018) * 4; - normalized = t.norm(raw, low, high); - - for (let i = 0; i <= 36; i++) { - const u = i / 36; - const x = -18 + i; - t.push(); - t.translate(x, 4); - t.char(u <= t.constrain(normalized, 0, 1) ? '#' : '.'); - t.charColor(80 + u * 160, 140 + u * 100, 255 - u * 100); - t.point(); - t.pop(); - } - - t.char('|'); - t.charColor(255, 210, 100); - const marker = t.map(t.constrain(normalized, 0, 1), 0, 1, low, high); - t.line(marker, -7, marker, 9); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.NORM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RANGE TO 0..1', x, y++, 100, 220, 255); - drawText('norm(value, low, high) scales.', x, y++, 140, 160, 190); - drawText('This bar clamps only for display.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`NORM: ${normalized.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/ortho.md b/api/textmode.js/classes/Textmodifier/methods/ortho.md index 7925a172..28a4fbe6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ortho.md +++ b/api/textmode.js/classes/Textmodifier/methods/ortho.md @@ -38,55 +38,5 @@ The projection mode is reset to perspective at the beginning of each frame. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - t.ortho(); - t.camera(0, 0, 42); - for (let i = 0; i < 3; i++) { - t.push(); - t.translate((i - 1) * 9, 0, i * -12); - t.rotateY(t.frameCount + i * 35); - t.char('+'); - t.charColor(120 + i * 40, 220, 255); - t.box(6, 6, 6); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ORTHO', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORTHO PROJECTION', x, y++, 100, 220, 255); - drawText('Depth no longer changes scale.', x, y++, 140, 160, 190); - drawText('Boxes keep equal apparent size.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.ortho()', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/perspective.md b/api/textmode.js/classes/Textmodifier/methods/perspective.md index 7ee913bb..fad2d1c6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/perspective.md +++ b/api/textmode.js/classes/Textmodifier/methods/perspective.md @@ -39,57 +39,5 @@ The default perspective is tuned to match textmode.js legacy depth behavior. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let fov = 60; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - fov = 60 + Math.sin(t.frameCount * 0.03) * 25; - t.perspective(fov, 0.1, 4096); - t.camera(0, 0, 44, 0, 0, 0); - for (let i = 0; i < 3; i++) { - t.push(); - t.translate((i - 1) * 8, 0, i * -12); - t.char('#'); - t.charColor(120 + i * 40, 220, 255 - i * 20); - t.box(6, 6, 6); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.PERSPECTIVE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FOV PROJECTION', x, y++, 100, 220, 255); - drawText('FOV breathes wide to narrow.', x, y++, 140, 160, 190); - drawText('Depth changes apparent size.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FOV: ${fov.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/pinch.md b/api/textmode.js/classes/Textmodifier/methods/pinch.md index 0faf89d5..05f83004 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pinch.md +++ b/api/textmode.js/classes/Textmodifier/methods/pinch.md @@ -35,60 +35,5 @@ the initial distance and the change since the previous update, enabling zoom int ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let scale = 1; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.pinch((data) => { - scale = Math.max(0.3, Math.min(4, data.scale)); -}); - -t.mouseScrolled((data) => { - scale = Math.max(0.3, Math.min(4, scale - data.delta.y * 0.01)); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.push(); - t.rotateZ(t.frameCount * 0.5); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(8 * scale, 8 * scale); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.PINCH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PINCH SCALE', x, y++, 100, 220, 255); - drawText('Pinch or scroll changes scale.', x, y++, 140, 160, 190); - drawText('Shape size follows gesture.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SCALE: ${scale.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md index b29b42b5..92d6371d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md +++ b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md @@ -30,90 +30,7 @@ Current pixel density. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let density = 1; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - density = density === 1 ? 2 : 1; - t.pixelDensity(density); -}); - -t.draw(() => { - t.background(6, 10, 22); - - // Crosshair pattern: higher pixel density yields finer lines. - const step = 4; - const max = 18; - t.cellColor(20, 25, 45); - for (let i = -max; i <= max; i += step) { - t.rect(1, 1); - t.translate(1, 0); - t.point(); - } - for (let i = -max; i <= max; i += step) { - t.push(); - t.translate(0, i); - t.rect(1, 1); - t.pop(); - } - - // Diagonal stepped line: smoother at higher resolution. - t.cellColor(60, 140, 200); - t.push(); - t.translate(-4, -4); - for (let i = 0; i < 9; i++) { - t.char('#'); - t.point(); - t.translate(1, 1); - } - t.pop(); - - // Pulse ring that reveals grid density. - const radius = 8 + Math.sin(t.frameCount * 0.05) * 3; - t.cellColor(200, 120, 60); - t.char('*'); - t.charColor(200, 120, 60); - t.ellipse(radius * 2, radius); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.PIXELDENSITY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RETINA RENDERING', x, y++, 100, 220, 255); - drawText('Click to toggle pixel density.', x, y++, 140, 160, 190); - drawText('Backing store scales, CSS fixed.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DENSITY: ${t.pixelDensity()}x`, x, y++, 140, 255, 180); - drawText(`BACKING: ${t.width}x${t.height}`, x, y++, 140, 255, 180); - drawText(`GRID: ${t.grid.cols}x${t.grid.rows}`, x, y++, 100, 200, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -137,87 +54,5 @@ This resizes the canvas backing store while keeping the CSS display size unchang ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let density = 1; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - density = density === 1 ? 2 : 1; - t.pixelDensity(density); -}); - -t.draw(() => { - t.background(6, 10, 22); - - // Crosshair pattern: higher pixel density yields finer lines. - const step = 4; - const max = 18; - t.cellColor(20, 25, 45); - for (let i = -max; i <= max; i += step) { - t.rect(1, 1); - t.translate(1, 0); - t.point(); - } - for (let i = -max; i <= max; i += step) { - t.push(); - t.translate(0, i); - t.rect(1, 1); - t.pop(); - } - - // Diagonal stepped line: smoother at higher resolution. - t.cellColor(60, 140, 200); - t.push(); - t.translate(-4, -4); - for (let i = 0; i < 9; i++) { - t.char('#'); - t.point(); - t.translate(1, 1); - } - t.pop(); - - // Pulse ring that reveals grid density. - const radius = 8 + Math.sin(t.frameCount * 0.05) * 3; - t.cellColor(200, 120, 60); - t.char('*'); - t.charColor(200, 120, 60); - t.ellipse(radius * 2, radius); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.PIXELDENSITY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RETINA RENDERING', x, y++, 100, 220, 255); - drawText('Click to toggle pixel density.', x, y++, 140, 160, 190); - drawText('Backing store scales, CSS fixed.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DENSITY: ${t.pixelDensity()}x`, x, y++, 140, 255, 180); - drawText(`BACKING: ${t.width}x${t.height}`, x, y++, 140, 255, 180); - drawText(`GRID: ${t.grid.cols}x${t.grid.rows}`, x, y++, 100, 200, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/point.md b/api/textmode.js/classes/Textmodifier/methods/point.md index 44cd8323..7e60ace6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/point.md +++ b/api/textmode.js/classes/Textmodifier/methods/point.md @@ -26,55 +26,5 @@ Draw one cell with the current settings. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const count = 24; - for (let i = 0; i < count; i++) { - const angle = t.frameCount * 0.03 + (i / count) * Math.PI * 2; - const radius = 5 + (i % 4) * 2; - t.push(); - t.translate(Math.cos(angle) * radius * 1.6, Math.sin(angle) * radius); - t.char(i % 2 === 0 ? '+' : '.'); - t.charColor(120 + i * 4, 180, 255 - i * 3); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POINT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DRAW ONE CELL', x, y++, 100, 220, 255); - drawText('point() stamps the active glyph.', x, y++, 140, 160, 190); - drawText('Each dot uses its own transform.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.point()', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/pointLight.md b/api/textmode.js/classes/Textmodifier/methods/pointLight.md index 6179a6f8..9ba2c979 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pointLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/pointLight.md @@ -48,59 +48,7 @@ Up to five point lights are supported per frame. Additional calls are ignored. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - value = 0.5 + 0.5 * Math.sin(time); - t.perspective(58, 0.1, 4096); - t.camera(16, -10, 42, 0, 0, 0); - t.ambientLight(20, 20, 28); - t.pointLight([255, 210, 120], { x: Math.sin(time) * 24, y: -18, z: 28 }); - t.rotateY(time * 40); - t.char('#'); - t.charColor(140, 220, 255); - t.sphere(7); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POINTLIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POINT LIGHT', x, y++, 100, 220, 255); - drawText('Lighting changes surface shade.', x, y++, 140, 160, 190); - drawText('Scene keeps focus on one sphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SWEEP: ${value.toFixed(2)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/pop.md b/api/textmode.js/classes/Textmodifier/methods/pop.md index b3a64fe8..f502393b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pop.md +++ b/api/textmode.js/classes/Textmodifier/methods/pop.md @@ -27,55 +27,5 @@ Use with [push](push.md) to isolate style changes within a block. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - t.push(); - t.rotateZ(time * 30); - t.translate(10, 0); - t.char('#'); - t.charColor(140, 255, 180); - t.rect(4, 3); - t.pop(); - t.charColor(255, 210, 120); - t.char('+'); - t.rect(5, 1); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESTORE STATE', x, y++, 100, 220, 255); - drawText('pop() returns to prior state.', x, y++, 140, 160, 190); - drawText('Center mark is not rotated.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.pop()', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/pow.md b/api/textmode.js/classes/Textmodifier/methods/pow.md index 55ebd98a..c54cf5fb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pow.md +++ b/api/textmode.js/classes/Textmodifier/methods/pow.md @@ -35,64 +35,5 @@ Base raised to the exponent. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let exponent = 1; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 17); - exponent = 0.5 + t.norm(t.sin(t.frameCount * 0.03) + t.cos(t.frameCount * 0.017) * 0.4, -1.4, 1.4) * 3; - - for (let i = 0; i <= 40; i++) { - const u = i / 40; - const shaped = t.pow(u, exponent); - const x = -20 + i; - const y = 8 - shaped * 16; - const heat = shaped; - t.push(); - t.translate(x, y); - t.char(heat > 0.7 ? '#' : heat > 0.3 ? '+' : '.'); - t.charColor(90 + heat * 150, 150 + heat * 80, 255 - heat * 90); - t.point(); - t.pop(); - } - - t.char('-'); - t.charColor(65, 85, 125); - t.line(-20, 8, 20, 8); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POW', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CURVE SHAPING', x, y++, 100, 220, 255); - drawText('pow(base, exp) bends 0..1.', x, y++, 140, 160, 190); - drawText('Small exponents lift the curve.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`EXPONENT: ${exponent.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/print.md b/api/textmode.js/classes/Textmodifier/methods/print.md index 29f42df9..abf6df43 100644 --- a/api/textmode.js/classes/Textmodifier/methods/print.md +++ b/api/textmode.js/classes/Textmodifier/methods/print.md @@ -46,72 +46,5 @@ like `[fg=red]`, `[bg=color]`, `[inv]`, `[rot=90]`, `[fx]`, `[fy]`, and their cl ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 22); - - // Subtle dynamic background particles - for (let i = 0; i < 15; i++) { - const angle = t.frameCount * 0.02 + i; - const radius = 8 + (i % 3) * 2.5; - t.push(); - t.translate(Math.cos(angle) * radius * 1.6, Math.sin(angle) * radius); - t.charColor(30, 45, 80); - t.char(i % 2 === 0 ? '.' : '+'); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.charColor(100, 255, 140); - t.print('TEXTMODIFIER.PRINT', x, y++); - t.pop(); - - t.push(); - t.charColor(80, 100, 150); - t.print('------------------------------------', x, y++); - t.pop(); - - t.push(); - t.charColor(100, 220, 255); - t.print('CONCEPT: NATIVE RICH TYPOGRAPHY', x, y++); - t.pop(); - - t.push(); - t.charColor(140, 160, 190); - t.print('Prints strings with inline BBCode-style tags:', x, y++); - t.print(' - [fg=green]Foreground Color[/fg]', x, y++); - t.print(' - [bg=blue]Background Color[/bg]', x, y++); - t.print(' - [inv]Inverted colors[/inv]', x, y++); - t.print(' - [rot=90]Rotated[/rot] [fx]Flip X[/fx] [fy]Flip Y[/fy]', x, y++); - t.pop(); - - t.push(); - t.charColor(80, 100, 150); - t.print('------------------------------------', x, y++); - t.pop(); - - t.print('NESTED: [fg=yellow][inv][rot=180] LEVEL 05 [/rot][/inv][/fg] | STATUS: [fg=red]CRITICAL[/fg]', x, y++); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/printAlign.md b/api/textmode.js/classes/Textmodifier/methods/printAlign.md index 8da83594..46a7c0b1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/printAlign.md +++ b/api/textmode.js/classes/Textmodifier/methods/printAlign.md @@ -33,99 +33,5 @@ Sets the text alignment rules for subsequent `print` calls. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); -const labelLayer = t.layers.add(); - -const alignments = [ - ['left', 'top'], - ['center', 'top'], - ['right', 'top'], - ['left', 'middle'], - ['center', 'middle'], - ['right', 'middle'], - ['left', 'bottom'], - ['center', 'bottom'], - ['right', 'bottom'], -]; - -const placementAlign = { left: 'right', center: 'center', right: 'left' }; -const placementVerticalAlign = { top: 'bottom', middle: 'middle', bottom: 'top' }; - -t.draw(() => { - t.background(6, 10, 22); - - const cols = t.grid.cols; - const rows = t.grid.rows; - t.push(); - t.charColor(20, 25, 45); - for (let y = -Math.floor(rows / 2); y < Math.floor(rows / 2); y += 4) { - for (let x = -Math.floor(cols / 2); x < Math.floor(cols / 2); x += 4) { - t.push(); - t.translate(x, y); - t.char('+'); - t.point(); - t.pop(); - } - } - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - const bottom = Math.floor(t.grid.rows / 2); - const index = Math.floor(t.frameCount / 90) % alignments.length; - const [h, v] = alignments[index]; - const label = `${h}, ${v}`; - const labelX = h === 'left' ? -1 : h === 'right' ? 1 : 0; - const labelY = v === 'top' ? -1 : v === 'bottom' ? 1 : 0; - - t.push(); - t.char('O'); - t.charColor(255, 100, 100); - t.invert(true); - t.point(); - t.pop(); - - t.push(); - t.printAlign(placementAlign[h], placementVerticalAlign[v]); - t.charColor(100, 220, 255); - t.print( - `ALIGNMENT: [fg=yellow][inv] ${label.toUpperCase()} [/inv][/fg]\nAnchor: (0, 0)\nLines: 5\nHorizontal: ${h}\nVertical: ${v}`, - labelX, - labelY - ); - t.pop(); - - t.push(); - t.printAlign('center', 'top'); - t.charColor(100, 255, 140); - t.print('TEXTMODIFIER.PRINTALIGN', 0, top + 2); - - t.charColor(80, 100, 150); - t.print('------------------------------------------------', 0, top + 3); - - t.charColor(140, 160, 190); - t.print('Anchored typography positioning demo. \nCycles automatically.', 0, top + 4); - t.pop(); - - t.push(); - t.printAlign('center', 'bottom'); - t.charColor(80, 100, 150); - t.print('------------------------------------------------', 0, bottom - 3); - t.charColor(120, 130, 150); - t.print(`Active state: ${index + 1} of ${alignments.length} | Frame: ${t.frameCount}`, 0, bottom - 2); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/push.md b/api/textmode.js/classes/Textmodifier/methods/push.md index 53437ae0..19bbf2af 100644 --- a/api/textmode.js/classes/Textmodifier/methods/push.md +++ b/api/textmode.js/classes/Textmodifier/methods/push.md @@ -27,57 +27,5 @@ Use with [pop](pop.md) to isolate style changes within a block. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - for (let i = 0; i < 5; i++) { - t.push(); - t.rotateZ(time * 20 + i * 72); - t.translate(8 + i, 0); - t.char('*'); - t.charColor(120 + i * 20, 220, 255 - i * 20); - t.point(); - t.pop(); - } - t.charColor(255, 210, 120); - t.char('+'); - t.point(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.PUSH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SAVE STATE', x, y++, 100, 220, 255); - drawText('push() stores transform state.', x, y++, 140, 160, 190); - drawText('Each spoke restores cleanly.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.push()', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/radians.md b/api/textmode.js/classes/Textmodifier/methods/radians.md index f5766b72..d769dd6c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/radians.md +++ b/api/textmode.js/classes/Textmodifier/methods/radians.md @@ -34,76 +34,5 @@ Angle in radians. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let angle = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawPoint(x, y) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); -} - -t.draw(() => { - t.background(7, 9, 18); - angle = (t.frameCount * 2 + t.mouse.x * 2) % 360; - const radians = t.radians(angle); - - t.char('.'); - t.charColor(45, 55, 86); - for (let r = 3; r <= 9; r += 3) t.ellipse(r * 2, r * 2); - - for (let i = 0; i < 10; i++) { - const a = radians + i * 0.45; - const radius = 3 + i * 0.65; - const x = Math.cos(a) * radius; - const y = Math.sin(a) * radius; - const fade = t.map(i, 0, 9, 255, 80); - t.char(i === 0 ? '@' : '+'); - t.charColor(120, fade, 255 - i * 10); - drawPoint(x, y); - } - - t.push(); - t.rotate(angle); - t.char('>'); - t.charColor(255, 220, 120); - t.line(0, 0, 10, 0); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RADIANS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DEGREE TO RADIAN', x, y++, 100, 220, 255); - drawText('radians() feeds sin and cos.', x, y++, 140, 160, 190); - drawText('The spiral uses circular math.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ANGLE: ${angle.toFixed(1)} DEG`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/random.md b/api/textmode.js/classes/Textmodifier/methods/random.md index aa2815cc..753ee3f0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/random.md +++ b/api/textmode.js/classes/Textmodifier/methods/random.md @@ -34,65 +34,7 @@ Random number in the range [0, 1). ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'random-demo', -}); - -const labelLayer = t.layers.add(); -const characters = Array.from('░▒▓█+*#'); -let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (t.frameCount % 12 === 1) { - mark = { - x: Math.floor(t.random(-18, 18)), - y: Math.floor(t.random(-9, 9)), - char: t.random(characters) ?? '*', - r: Math.floor(t.random(120, 256)), - g: Math.floor(t.random(120, 256)), - b: Math.floor(t.random(120, 256)), - }; - } - - t.push(); - t.translate(mark.x, mark.y); - t.char(mark.char); - t.charColor(mark.r, mark.g, mark.b); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); - drawText('The mark uses random ranges.', x, y++, 140, 160, 190); - drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -116,65 +58,7 @@ Random number in the range [0, max). ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'random-demo', -}); - -const labelLayer = t.layers.add(); -const characters = Array.from('░▒▓█+*#'); -let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (t.frameCount % 12 === 1) { - mark = { - x: Math.floor(t.random(-18, 18)), - y: Math.floor(t.random(-9, 9)), - char: t.random(characters) ?? '*', - r: Math.floor(t.random(120, 256)), - g: Math.floor(t.random(120, 256)), - b: Math.floor(t.random(120, 256)), - }; - } - - t.push(); - t.translate(mark.x, mark.y); - t.char(mark.char); - t.charColor(mark.r, mark.g, mark.b); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); - drawText('The mark uses random ranges.', x, y++, 140, 160, 190); - drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -199,65 +83,7 @@ Random number in the range [min, max). ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'random-demo', -}); - -const labelLayer = t.layers.add(); -const characters = Array.from('░▒▓█+*#'); -let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (t.frameCount % 12 === 1) { - mark = { - x: Math.floor(t.random(-18, 18)), - y: Math.floor(t.random(-9, 9)), - char: t.random(characters) ?? '*', - r: Math.floor(t.random(120, 256)), - g: Math.floor(t.random(120, 256)), - b: Math.floor(t.random(120, 256)), - }; - } - - t.push(); - t.translate(mark.x, mark.y); - t.char(mark.char); - t.charColor(mark.r, mark.g, mark.b); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); - drawText('The mark uses random ranges.', x, y++, 140, 160, 190); - drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -287,62 +113,5 @@ A random array element, or `undefined` when the array is empty. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'random-demo', -}); - -const labelLayer = t.layers.add(); -const characters = Array.from('░▒▓█+*#'); -let mark = { x: 0, y: 0, char: '*', r: 255, g: 255, b: 255 }; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (t.frameCount % 12 === 1) { - mark = { - x: Math.floor(t.random(-18, 18)), - y: Math.floor(t.random(-9, 9)), - char: t.random(characters) ?? '*', - r: Math.floor(t.random(120, 256)), - g: Math.floor(t.random(120, 256)), - b: Math.floor(t.random(120, 256)), - }; - } - - t.push(); - t.translate(mark.x, mark.y); - t.char(mark.char); - t.charColor(mark.r, mark.g, mark.b); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEDED CHOICES', x, y++, 100, 220, 255); - drawText('The mark uses random ranges.', x, y++, 140, 160, 190); - drawText('The seed repeats this sequence.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md index 24f49239..c4d7c6b2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md @@ -39,83 +39,5 @@ Gaussian random number. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'gaussian-cloud', -}); - -const labelLayer = t.layers.add(); -const samples = []; -let latest = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addSample() { - latest = t.randomGaussian(0, 6); - samples.push(latest); - if (samples.length > 180) { - samples.shift(); - } -} - -t.draw(() => { - t.background(4, 7, 16); - for (let i = 0; i < 4; i++) { - addSample(); - } - - t.char('.'); - t.charColor(45, 60, 95); - for (let x = -24; x <= 24; x += 2) { - t.line(x, 9, x, 10); - } - - for (let i = 0; i < samples.length; i++) { - const age = i / samples.length; - const x = t.constrain(t.round(samples[i]), -24, 24); - const y = 8 - t.floor(age * 16); - t.push(); - t.translate(x, y); - t.char(age > 0.7 ? '*' : age > 0.35 ? '+' : '.'); - t.charColor(90 + age * 140, 150 + age * 90, 255); - t.point(); - t.pop(); - } - - t.char('|'); - t.charColor(255, 205, 90); - t.line(0, -10, 0, 10); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.RANDOMGAUSSIAN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SEEDED BELL CURVE', x, y++, 100, 220, 255); - drawText('Most samples gather near mean 0.', x, y++, 140, 160, 190); - drawText('Standard deviation sets spread.', x, y++, 140, 160, 190); - drawText('The sequence is reproducible.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`LATEST: ${latest.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`SAMPLES: ${samples.length}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md index f68f9097..2f3068d6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md @@ -35,69 +35,5 @@ stream lookups are derived from the new root seed. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const points = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function rebuildPoints() { - t.randomSeed('repeatable-grid'); - points.length = 0; - for (let i = 0; i < 28; i++) { - points.push({ - x: Math.floor(t.random(-20, 20)), - y: Math.floor(t.random(-9, 9)), - char: t.random(['.', '+', '*', '#']) ?? '.', - }); - } -} - -rebuildPoints(); - -t.draw(() => { - t.background(8, 7, 18); - if (t.frameCount % 120 === 1) { - rebuildPoints(); - } - - for (const point of points) { - t.push(); - t.translate(point.x, point.y); - t.char(point.char); - t.charColor(120, 240, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOMSEED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESET SEQUENCE', x, y++, 100, 220, 255); - drawText('The same points return.', x, y++, 140, 160, 190); - drawText('The seed is set every loop.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/randomStream.md b/api/textmode.js/classes/Textmodifier/methods/randomStream.md index 821030c3..07d45910 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomStream.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomStream.md @@ -37,62 +37,5 @@ A deterministic random generator for the given stream name. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - seed: 'stream-demo', -}); - -const labelLayer = t.layers.add(); -const leftStream = t.randomStream('left'); -const rightStream = t.randomStream('right'); -let leftY = 0; -let rightY = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 18); - if (t.frameCount % 16 === 1) { - leftY = Math.floor(leftStream.random(-9, 9)); - rightY = Math.floor(rightStream.random(-9, 9)); - } - - t.push(); - t.translate(-8, leftY); - t.char('L'); - t.charColor(130, 255, 190); - t.point(); - t.translate(16, rightY - leftY); - t.char('R'); - t.charColor(255, 190, 130); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RANDOMSTREAM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: NAMED STREAMS', x, y++, 100, 220, 255); - drawText('Left and right are separate.', x, y++, 140, 160, 190); - drawText('One stream cannot move another.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/rect.md b/api/textmode.js/classes/Textmodifier/methods/rect.md index 4e9ca472..0508fdec 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rect.md +++ b/api/textmode.js/classes/Textmodifier/methods/rect.md @@ -34,59 +34,5 @@ Position is controlled via [translate](translate.md), [push](push.md), and [pop] ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let widthCells = 0; -let heightCells = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - widthCells = 12 + Math.round(Math.sin(time) * 5); - heightCells = 6 + Math.round(Math.cos(time * 0.8) * 3); - t.push(); - t.translate(8, 1); - t.rotateZ(Math.sin(time) * 8); - t.char('#'); - t.charColor(120, 220, 255); - t.cellColor(20, 30, 60); - t.rect(widthCells, heightCells); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RECT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RECTANGLE SHAPE', x, y++, 100, 220, 255); - drawText('Draws width by height cells.', x, y++, 140, 160, 190); - drawText('Scene shifted clear of the HUD.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`W: ${widthCells}`, x, y++, 140, 255, 180); - drawText(`H: ${heightCells}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/redraw.md b/api/textmode.js/classes/Textmodifier/methods/redraw.md index 024a063e..0f1fb4b9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/redraw.md +++ b/api/textmode.js/classes/Textmodifier/methods/redraw.md @@ -35,79 +35,5 @@ allowing you to trigger rendering on demand. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let steps = 0; -let lastRequest = 1; - -t.setup(() => { - t.noLoop(); -}); - -t.mousePressed(() => { - lastRequest = 1; - t.redraw(); -}); - -t.keyPressed(() => { - lastRequest = 5; - t.redraw(5); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - steps++; - t.background(6, 8, 14); - - const width = Math.max(12, Math.floor(t.grid.cols * 0.6)); - for (let i = 0; i < width; i++) { - const phase = steps * 0.32 + i * 0.45; - const x = i - Math.floor(width / 2); - const y = Math.round(Math.sin(phase) * 5); - t.push(); - t.translate(x, y + 2); - t.char(i % 3 === 0 ? '+' : '*'); - t.charColor(90 + (i % 12) * 12, 200, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.REDRAW', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MANUAL RENDER STEPS', x, y++, 100, 220, 255); - drawText('setup pauses with noLoop().', x, y++, 140, 160, 190); - drawText('redraw(n) renders n frames.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FRAMES: ${steps}`, x, y++, 140, 255, 180); - drawText(`LAST REQUEST: ${lastRequest}`, x, y++, 255, 225, 140); - drawText('CLICK: REDRAW 1', x, y++, 255, 225, 140); - drawText('ANY KEY: REDRAW 5', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md index a81bcc4b..65a03198 100644 --- a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md @@ -33,97 +33,5 @@ otherwise `false`. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let rotX = 0, - rotY = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (document.pointerLockElement === t.canvas) t.exitPointerLock(); - else t.requestPointerLock(); -}); - -t.draw(() => { - t.background(5, 8, 10); - const isLocked = document.pointerLockElement === t.canvas; - - if (isLocked) { - rotX += t.movedX * 0.35; - rotY += t.movedY * 0.35; - } else { - rotX += 0.25; - } - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const rad = Math.floor(Math.min(hw, hh) * 0.65); - const angleOffset = (rotX * 0.05) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y * 1.4); - const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; - - let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; - let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); - let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; - - if (isRing || isAxis || isTick) { - t.push(); - t.translate(x, y); - - if (isLocked) { - if (d < 3) { - t.charColor(255, 51, 51); - t.cellColor(90, 0, 0); - t.char('+'); - } else if (isTick) { - t.charColor(255, 200, 0); - t.char('#'); - } else { - t.charColor(255, 153, 0); - t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); - } - } else { - t.charColor(68, 85, 102); - t.char(isAxis ? '+' : '.'); - } - - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isLocked = document.pointerLockElement === t.canvas; - - drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); - drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); - drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); - drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); - drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md index 6c550c3b..d4cb7ddf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md @@ -28,56 +28,5 @@ This clears any active explicit camera and returns view calculation to renderer- ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let custom = true; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - custom = Math.floor(t.frameCount / 120) % 2 === 0; - if (custom) { - t.camera(Math.sin(t.frameCount * 0.03) * 20, 10, 38, 0, 0, 0); - } else { - t.resetCamera(); - } - t.char('#'); - t.charColor(140, 220, 255); - t.rotateY(t.frameCount); - t.box(8, 8, 8); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RESETCAMERA', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESTORE CAMERA', x, y++, 100, 220, 255); - drawText('Alternates custom and reset.', x, y++, 140, 160, 190); - drawText('resetCamera returns auto view.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(custom ? 'MODE: CUSTOM' : 'MODE: RESET', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md index f37deea7..9357366f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md @@ -28,57 +28,5 @@ This clears translation, rotation, and scale state for subsequent draw calls. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.04; - t.push(); - t.rotateZ(time * 40); - t.translate(12, 0); - t.charColor(120, 220, 255); - t.char('#'); - t.rect(6, 3); - t.resetMatrix(); - t.charColor(255, 210, 120); - t.translate(8, 3); - t.char('+'); - t.rect(5, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RESETMATRIX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLEAR TRANSFORM', x, y++, 100, 220, 255); - drawText('resetMatrix drops transforms.', x, y++, 140, 160, 190); - drawText('Yellow bar uses fresh matrix.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.resetMatrix()', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/resetShader.md b/api/textmode.js/classes/Textmodifier/methods/resetShader.md index 9bf9a0c8..1afd5768 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetShader.md @@ -29,72 +29,5 @@ Equivalent to calling `shader(null)`. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let shaderObj; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_texCoord; - out vec2 v_uv; - void main(){gl_Position=a_position;v_uv=a_texCoord;}`; - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform float u_time; - layout(location=0) out vec4 o_character; - layout(location=1) out vec4 o_primaryColor; - layout(location=2) out vec4 o_secondaryColor; - void main(){float v=fract(v_uv.x*8.0+u_time);o_character=vec4(v,0,0,1);o_primaryColor=vec4(v,0.8,1.0,1);o_secondaryColor=vec4(0.02,0.04,0.08,1);}`; - shaderObj = await t.createShader(vert, frag); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (shaderObj && Math.floor(t.frameCount / 90) % 2 === 0) { - t.shader(shaderObj); - t.setUniform('u_time', t.frameCount * 0.02); - } - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); - t.char('#'); - t.charColor(255, 210, 120); - t.rect(10, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RESETSHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESTORE SHADER', x, y++, 100, 220, 255); - drawText('Shader affects the main drawing.', x, y++, 140, 160, 190); - drawText('resetShader restores default.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('RESET AFTER FULLSCREEN', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md index dbf0ebf1..35e721cf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md +++ b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md @@ -33,54 +33,5 @@ Resize the canvas and adjust all related components accordingly. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let resized = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.mouseClicked(() => { - resized++; - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.RESIZECANVAS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESIZE CANVAS', x, y++, 100, 220, 255); - drawText('Click calls resizeCanvas.', x, y++, 140, 160, 190); - drawText('Window callback does the same.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CLICKS: ${resized}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/rotate.md b/api/textmode.js/classes/Textmodifier/methods/rotate.md index c86e6d38..3e016ae2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotate.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotate.md @@ -30,78 +30,7 @@ All geometries rotate around the center of the shape. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 8, 20); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.04; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const angle = Math.atan2(y, x); - - const wave = Math.sin(dist * 0.25 - tm * 2) * Math.cos(angle * 6 + tm); - const norm = (wave + 1) * 0.5; - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.rotate(Math.sin(tm * 0.5) * 0.2); - t.translate(x, y); - t.charColor(Math.floor(80 + norm * 175), Math.floor(180 + norm * 75), Math.floor(255 - norm * 100)); - t.cellColor(Math.floor(6 + norm * 12), Math.floor(12 + norm * 14), Math.floor(28 + norm * 18)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.ROTATE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: MOIRE SPIROGRAPH CITADEL', x, y++); - t.charColor(140, 160, 190); - t.print('Rotates current coordinate space', x, y++); - t.print('by specified angle in 2D plane.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('ROTATION: FULL-SCREEN HARMONIC MOIRE', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md index 449ce5e2..91ba4265 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md @@ -35,64 +35,5 @@ along with the gesture centre in grid coordinates. Ideal for dial-like interacti ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let rotation = 0; -let dragStart = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.rotateGesture((data) => { - rotation += data.deltaRotation; -}); - -t.mousePressed(() => { - dragStart = t.mouse.x; -}); - -t.mouseDragged(() => { - rotation += (t.mouse.x - dragStart) * 0.5; - dragStart = t.mouse.x; -}); - -t.draw(() => { - t.background(6, 10, 22); - t.rotateZ(rotation); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(14, 4); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ROTATEGESTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ROTATE GESTURE', x, y++, 100, 220, 255); - drawText('Touch twist or drag rotates.', x, y++, 140, 160, 190); - drawText('Rotation accumulates over time.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DEG: ${rotation.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateX.md b/api/textmode.js/classes/Textmodifier/methods/rotateX.md index f57542dc..b6911c70 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateX.md @@ -36,58 +36,5 @@ Current X-axis rotation in degrees when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.04; - value = (time * 70) % 360; - t.charColor(50, 60, 90); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - t.push(); - t.rotateX(value); - t.char('#'); - t.charColor(140, 255, 180); - t.rect(6, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ROTATEX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: X AXIS ROTATION', x, y++, 100, 220, 255); - drawText('Pitch changes vertical plane.', x, y++, 140, 160, 190); - drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateY.md b/api/textmode.js/classes/Textmodifier/methods/rotateY.md index 4c2ca0ad..84a59c55 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateY.md @@ -36,58 +36,5 @@ Current Y-axis rotation in degrees when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.04; - value = (time * 70) % 360; - t.charColor(50, 60, 90); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - t.push(); - t.rotateY(value); - t.char('#'); - t.charColor(140, 255, 180); - t.rect(6, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ROTATEY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: Y AXIS ROTATION', x, y++, 100, 220, 255); - drawText('Yaw turns the rectangle.', x, y++, 140, 160, 190); - drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md index 96c799e4..ff62b38e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md @@ -36,58 +36,5 @@ Current Z-axis rotation in degrees when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.04; - value = (time * 70) % 360; - t.charColor(50, 60, 90); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - t.push(); - t.rotateZ(value); - t.char('#'); - t.charColor(140, 255, 180); - t.rect(6, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ROTATEZ', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: Z AXIS ROTATION', x, y++, 100, 220, 255); - drawText('Roll matches 2D rotation.', x, y++, 140, 160, 190); - drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DEG: ${value.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/round.md b/api/textmode.js/classes/Textmodifier/methods/round.md index b25aba48..03c41731 100644 --- a/api/textmode.js/classes/Textmodifier/methods/round.md +++ b/api/textmode.js/classes/Textmodifier/methods/round.md @@ -35,69 +35,5 @@ Rounded value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let raw = 0; -let coarse = 0; -let decimal = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 16); - raw = t.sin(t.frameCount * 0.037) * 12 + t.cos(t.frameCount * 0.019) * 3; - coarse = t.round(raw); - decimal = t.round(raw, 1); - - for (let x = -22; x <= 22; x++) { - const isCoarse = x === coarse; - t.push(); - t.translate(x, 2 + t.sin(x * 0.4 + t.frameCount * 0.04) * 4); - t.char(isCoarse ? '#' : '.'); - t.charColor(isCoarse ? 255 : 55, isCoarse ? 215 : 80, isCoarse ? 100 : 120); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(120, 245, 255); - t.push(); - t.translate(decimal, -6); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.ROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: NEAREST VALUE', x, y++, 100, 220, 255); - drawText('round() snaps to the closest cell.', x, y++, 140, 160, 190); - drawText('round(value, 1) keeps one decimal.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RAW: ${raw.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`ROUND: ${coarse}`, x, y++, 220, 230, 255); - drawText(`ROUND.1: ${decimal.toFixed(1)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/scale.md b/api/textmode.js/classes/Textmodifier/methods/scale.md index dd9c16c0..1ffb5029 100644 --- a/api/textmode.js/classes/Textmodifier/methods/scale.md +++ b/api/textmode.js/classes/Textmodifier/methods/scale.md @@ -37,76 +37,5 @@ Scale subsequent geometry in model space. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.04; - - const sx = 1 + Math.sin(tm * 1.5) * 0.4; - const sy = 1 + Math.cos(tm * 1.2) * 0.4; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const wave = Math.sin(dist * 0.25 - tm * 2) * Math.cos(x * 0.15 + y * 0.15); - const norm = (wave + 1) * 0.5; - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.scale(sx, sy, 1.0); - t.translate(x, y); - t.charColor(255, Math.floor(140 + sx * 60), Math.floor(100 + sy * 80)); - t.cellColor(Math.floor(8 + norm * 14), Math.floor(12 + norm * 16), Math.floor(28 + norm * 20)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.SCALE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: BREATHING CATHEDRAL LATTICE', x, y++); - t.charColor(140, 160, 190); - t.print('Scales current matrix by scale factors', x, y++); - t.print('along X, Y, and Z coordinate axes.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('TRANSFORM: NON-UNIFORM KINETIC SCALE', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/setCamera.md b/api/textmode.js/classes/Textmodifier/methods/setCamera.md index d35f4996..d6c07d38 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/setCamera.md @@ -32,69 +32,5 @@ Activate a previously created camera object. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let cameraA; -let cameraB; -let active = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - t.perspective(58, 0.1, 4096); - cameraA = t.createCamera(); - cameraA.setPosition(-28, 10, 36).lookAt(0, 0, 0); - cameraB = t.createCamera(); - cameraB.setPosition(28, 10, 36).lookAt(0, 0, 0); -}); - -t.draw(() => { - t.background(6, 8, 18); - active = Math.floor(t.frameCount / 120) % 2 === 0; - t.setCamera(active ? cameraA : cameraB); - t.ambientLight(25, 28, 36); - t.pointLight([255, 210, 140], { x: 18, y: -16, z: 28 }); - for (let i = 0; i < 3; i++) { - t.push(); - t.translate((i - 1) * 9, 0, i * -8); - t.rotateY(t.frameCount + i * 30); - t.char('#'); - t.charColor(120 + i * 40, 220, 255 - i * 20); - t.box(5, 5, 5); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SETCAMERA', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACTIVATE CAMERA', x, y++, 100, 220, 255); - drawText('Two camera objects alternate.', x, y++, 140, 160, 190); - drawText('Scene proves viewpoint change.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(active ? 'ACTIVE: CAMERA A' : 'ACTIVE: CAMERA B', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniform.md b/api/textmode.js/classes/Textmodifier/methods/setUniform.md index ec9519a2..b0da768e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniform.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniform.md @@ -33,74 +33,5 @@ Set a uniform value on the current custom shader. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let customShader = null; - -t.setup(async () => { - customShader = await t.createMaterialShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -uniform vec2 u_mouse; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); - float glyph = step(0.0, wave); - float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); - o_character = vec4(glyph, 0.0, 0.0, 1.0); - o_primaryColor = vec4(0.3, glow, 1.0, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); -}`); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(0); - if (!customShader) return; - t.shader(customShader); - const time = t.frameCount * 0.02; - const mx = (Math.sin(time) + 1) * 0.5; - const my = (Math.cos(time) + 1) * 0.5; - t.setUniform('u_time', time); - t.setUniform('u_mouse', [mx, my]); - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.SETUNIFORM', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); - drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('UNIFORM: u_time', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md index 4f8e6f6f..aa73a944 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md @@ -32,73 +32,5 @@ Set multiple uniform values on the current custom shader. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let customShader = null; - -t.setup(async () => { - customShader = await t.createMaterialShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -uniform vec2 u_mouse; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); - float glyph = step(0.0, wave); - float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); - o_character = vec4(glyph, 0.0, 0.0, 1.0); - o_primaryColor = vec4(0.3, glow, 1.0, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); -}`); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(0); - if (!customShader) return; - t.shader(customShader); - const time = t.frameCount * 0.02; - const mx = (Math.sin(time) + 1) * 0.5; - const my = (Math.cos(time) + 1) * 0.5; - t.setUniforms({ u_time: time, u_mouse: [mx, my] }); - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.SETUNIFORMS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); - drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('UNIFORMS: 2', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/setup.md b/api/textmode.js/classes/Textmodifier/methods/setup.md index 3f9edcfa..f48e4f7f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setup.md +++ b/api/textmode.js/classes/Textmodifier/methods/setup.md @@ -37,59 +37,5 @@ The callback can be asynchronous (return a Promise). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let seed = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - seed = Math.floor(Math.random() * 999); -}); - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - for (let i = 0; i < 8; i++) { - t.push(); - t.translate(Math.cos(time + i) * 12, Math.sin(time + i) * 6); - t.char(String((seed + i) % 10)); - t.charColor(120 + i * 12, 220, 255 - i * 10); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SETUP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ONE-TIME INIT', x, y++, 100, 220, 255); - drawText('setup() runs before drawing.', x, y++, 140, 160, 190); - drawText('Seed is created once.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SEED: ${seed}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/shader.md b/api/textmode.js/classes/Textmodifier/methods/shader.md index 06288522..2a9807ec 100644 --- a/api/textmode.js/classes/Textmodifier/methods/shader.md +++ b/api/textmode.js/classes/Textmodifier/methods/shader.md @@ -35,75 +35,5 @@ This behavior matches p5.js, allowing multiple draw calls with the same shader. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let customShader = null; - -t.setup(async () => { - customShader = await t.createMaterialShader(`#version 300 es -precision highp float; -in vec2 v_uv; -uniform float u_time; -uniform vec2 u_mouse; -layout(location = 0) out vec4 o_character; -layout(location = 1) out vec4 o_primaryColor; -layout(location = 2) out vec4 o_secondaryColor; -void main() { - float wave = sin((v_uv.x + v_uv.y + u_time) * 24.0); - float glyph = step(0.0, wave); - float glow = 0.4 + 0.6 * distance(v_uv, u_mouse); - o_character = vec4(glyph, 0.0, 0.0, 1.0); - o_primaryColor = vec4(0.3, glow, 1.0, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.08, 1.0); -}`); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(0); - if (!customShader) return; - t.shader(customShader); - const time = t.frameCount * 0.02; - const mx = (Math.sin(time) + 1) * 0.5; - const my = (Math.cos(time) + 1) * 0.5; - t.setUniform('u_time', time); - t.setUniform('u_mouse', [mx, my]); - t.rect(t.grid.cols, t.grid.rows); - t.resetShader(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.SHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM SHADER', x, y++, 100, 220, 255); - drawText('Uniforms drive GLSL state.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = customShader ? 'READY' : 'WAIT'; - drawText(`SHADER: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/sin.md b/api/textmode.js/classes/Textmodifier/methods/sin.md index f75ae6f3..211d8934 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sin.md +++ b/api/textmode.js/classes/Textmodifier/methods/sin.md @@ -36,72 +36,5 @@ Sine of the angle. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let phase = 0; -let sample = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(3, 7, 18); - phase = t.frameCount * 0.06; - const width = t.min(54, t.grid.cols - 8); - const amp = t.max(4, t.grid.rows * 0.18); - sample = t.sin(phase); - - for (let x = -t.floor(width / 2); x <= t.floor(width / 2); x++) { - const a = phase + x * 0.28; - const y = t.round(t.sin(a) * amp); - const pulse = t.norm(t.sin(a), -1, 1); - t.push(); - t.translate(x, y); - t.char(pulse > 0.7 ? '*' : pulse > 0.35 ? '+' : '.'); - t.charColor(70 + pulse * 170, 130 + pulse * 100, 255); - t.point(); - t.pop(); - } - - t.char('-'); - t.charColor(55, 75, 115); - t.line(-t.floor(width / 2), 0, t.floor(width / 2), 0); - t.char('@'); - t.charColor(255, 220, 100); - t.push(); - t.translate(0, t.round(sample * amp)); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SIN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SMOOTH OSCILLATION', x, y++, 100, 220, 255); - drawText('sin(angle) flows from -1 to 1.', x, y++, 140, 160, 190); - drawText('The yellow point samples phase.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SIN: ${sample.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/sphere.md b/api/textmode.js/classes/Textmodifier/methods/sphere.md index 4082623e..4525d984 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sphere.md +++ b/api/textmode.js/classes/Textmodifier/methods/sphere.md @@ -32,61 +32,5 @@ Draw a sphere mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.sphere(7); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SPHERE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D SPHERE', x, y++, 100, 220, 255); - drawText('Radius defines all axes.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/sq.md b/api/textmode.js/classes/Textmodifier/methods/sq.md index 91668208..191c948f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sq.md +++ b/api/textmode.js/classes/Textmodifier/methods/sq.md @@ -34,67 +34,5 @@ Value multiplied by itself. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let input = 0; -let squared = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - input = t.sin(t.frameCount * 0.035) * 8 + t.cos(t.frameCount * 0.02) * 2; - squared = t.sq(input); - - for (let x = -12; x <= 12; x++) { - const y = t.round(t.sq(x / 4) - 8); - const hot = t.norm(t.abs(x), 0, 12); - t.push(); - t.translate(x * 2, y); - t.char(hot > 0.7 ? '#' : '+'); - t.charColor(80 + hot * 160, 150, 255 - hot * 90); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(255, 220, 100); - t.push(); - t.translate(t.round(input * 2), t.round(squared / 8 - 8)); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SQ', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PARABOLIC GROWTH', x, y++, 100, 220, 255); - drawText('sq(x) multiplies x by itself.', x, y++, 140, 160, 190); - drawText('Negative and positive both rise.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`X: ${input.toFixed(2)}`, x, y++, 220, 230, 255); - drawText(`SQ: ${squared.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/sqrt.md b/api/textmode.js/classes/Textmodifier/methods/sqrt.md index 22391639..3db18219 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sqrt.md +++ b/api/textmode.js/classes/Textmodifier/methods/sqrt.md @@ -34,69 +34,5 @@ Square root of the value. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let value = 0; -let root = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(3, 8, 16); - value = t.norm(t.sin(t.frameCount * 0.035), -1, 1) * 64 + t.norm(t.cos(t.frameCount * 0.019), -1, 1) * 8; - root = t.sqrt(value); - - for (let i = 0; i < 32; i++) { - const v = i * 2; - const x = -24 + i * 1.5; - const y = 8 - t.sqrt(v) * 2; - const active = v <= value; - t.push(); - t.translate(x, y); - t.char(active ? '#' : '.'); - t.charColor(active ? 110 : 45, active ? 225 : 65, active ? 255 : 95); - t.point(); - t.pop(); - } - - t.char('@'); - t.charColor(255, 220, 100); - t.push(); - t.translate(-24 + value * 0.75, 8 - root * 2); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SQRT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: COMPRESSED GROWTH', x, y++, 100, 220, 255); - drawText('sqrt() grows quickly, then eases.', x, y++, 140, 160, 190); - drawText('The yellow sample climbs slowly.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`VALUE: ${value.toFixed(1)}`, x, y++, 220, 230, 255); - drawText(`SQRT: ${root.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/stroke.md b/api/textmode.js/classes/Textmodifier/methods/stroke.md index 4f7e8a6e..0fef519f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/stroke.md +++ b/api/textmode.js/classes/Textmodifier/methods/stroke.md @@ -30,54 +30,7 @@ Current character color. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); - t.fill(20, 30, 60); - t.stroke(red, 0, 0); - t.char('.'); - t.rect(14, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); - drawText('charColor colors shape edges.', x, y++, 140, 160, 190); - drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -100,54 +53,7 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using a gr ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); - t.fill(20, 30, 60); - t.stroke(red, 0, 0); - t.char('.'); - t.rect(14, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); - drawText('charColor colors shape edges.', x, y++, 140, 160, 190); - drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -176,54 +82,7 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using RGB( ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); - t.fill(20, 30, 60); - t.stroke(red, 0, 0); - t.char('.'); - t.rect(14, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); - drawText('charColor colors shape edges.', x, y++, 140, 160, 190); - drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -245,51 +104,5 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using a CS ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let red = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - red = Math.round(120 + 100 * Math.sin(t.frameCount * 0.04)); - t.fill(20, 30, 60); - t.stroke(red, 0, 0); - t.char('.'); - t.rect(14, 6); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.STROKE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHAPE OUTLINE', x, y++, 100, 220, 255); - drawText('charColor colors shape edges.', x, y++, 140, 160, 190); - drawText('cellColor controls interior cells.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`STROKE R: ${red}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/swipe.md b/api/textmode.js/classes/Textmodifier/methods/swipe.md index 3cc6f2fc..a86e75af 100644 --- a/api/textmode.js/classes/Textmodifier/methods/swipe.md +++ b/api/textmode.js/classes/Textmodifier/methods/swipe.md @@ -35,84 +35,5 @@ per millisecond. Useful for panning, flicks, or quick shortcuts. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const particles = []; -let last = 'NONE'; -let sx = 0; -let sy = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function launch(dx, dy) { - last = Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? 'RIGHT' : 'LEFT') : dy > 0 ? 'DOWN' : 'UP'; - for (let i = 0; i < 8; i++) particles.push({ x: 0, y: 0, vx: dx * (1 + i * 0.1), vy: dy * (1 + i * 0.1), life: 1 }); -} - -t.swipe((data) => { - launch(data.direction.x, data.direction.y); -}); - -t.mousePressed(() => { - sx = t.mouse.x; - sy = t.mouse.y; -}); - -t.mouseReleased(() => { - const dx = t.mouse.x - sx; - const dy = t.mouse.y - sy; - const len = Math.hypot(dx, dy); - if (len > 4) launch(dx / len, dy / len); -}); - -t.draw(() => { - t.background(6, 10, 22); - for (let i = particles.length - 1; i >= 0; i--) { - const p = particles[i]; - p.x += p.vx; - p.y += p.vy; - p.life -= 0.025; - if (p.life <= 0) particles.splice(i, 1); - t.push(); - t.translate(p.x, p.y); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.SWIPE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SWIPE DIRECTION', x, y++, 100, 220, 255); - drawText('Swipe or drag/release.', x, y++, 140, 160, 190); - drawText('Particles follow direction.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('LAST: ' + last, x, y++, 140, 255, 180); - drawText(`ACTIVE: ${particles.length}`, x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/tan.md b/api/textmode.js/classes/Textmodifier/methods/tan.md index 49b54879..1b34d46c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tan.md +++ b/api/textmode.js/classes/Textmodifier/methods/tan.md @@ -36,69 +36,5 @@ Tangent of the angle. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let angle = 0; -let tangent = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(8, 5, 17); - angle = t.sin(t.frameCount * 0.025) * t.radians(75); - tangent = t.tan(angle); - const slope = t.constrain(tangent, -5, 5); - - t.char('|'); - t.charColor(70, 80, 125); - t.line(-18, -10, -18, 10); - t.line(18, -10, 18, 10); - - for (let x = -18; x <= 18; x++) { - const y = t.round(t.constrain(t.tan(x * 0.08 + angle), -10, 10)); - const heat = t.norm(t.abs(y), 0, 10); - t.push(); - t.translate(x, y); - t.char(heat > 0.75 ? '#' : heat > 0.4 ? '+' : '.'); - t.charColor(90 + heat * 160, 120, 255 - heat * 80); - t.point(); - t.pop(); - } - - t.char('*'); - t.charColor(255, 215, 100); - t.line(-6, t.round(-slope * 3), 6, t.round(slope * 3)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -t.floor(t.grid.cols / 2); - const top = -t.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TAN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SLOPE AND ASYMPTOTES', x, y++, 100, 220, 255); - drawText('tan(angle) grows steep fast.', x, y++, 140, 160, 190); - drawText('Rails show the unstable edges.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TAN: ${tangent.toFixed(2)}`, x, y++, 220, 230, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/tap.md b/api/textmode.js/classes/Textmodifier/methods/tap.md index 9f682b6a..1ec1ef22 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tap.md +++ b/api/textmode.js/classes/Textmodifier/methods/tap.md @@ -35,76 +35,5 @@ Use [input.touch.TouchTapEventData.taps](../../../namespaces/input/namespaces/to ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.tap((data) => { - const touch = data?.touch || t.mouse; - addPulse('TAPS', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TAP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TAP GESTURE', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('TAPS: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md index 0b849bb8..c612632c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md @@ -36,56 +36,5 @@ Current target frame rate when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let target = 60; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - target = Math.floor(t.frameCount / 150) % 2 === 0 ? 24 : 60; - t.targetFrameRate(target); - for (let i = 0; i < target / 4; i++) { - t.push(); - t.translate(-18 + i, 3); - t.char('+'); - t.charColor(120, 220, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TARGETFRAMERATE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TARGET FPS', x, y++, 100, 220, 255); - drawText('Sets desired draw cadence.', x, y++, 140, 160, 190); - drawText('Readout is kept compact.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TARGET: ${t.targetFrameRate()}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/texture.md b/api/textmode.js/classes/Textmodifier/methods/texture.md index 95614d83..12c3d948 100644 --- a/api/textmode.js/classes/Textmodifier/methods/texture.md +++ b/api/textmode.js/classes/Textmodifier/methods/texture.md @@ -38,81 +38,7 @@ uses source conversion settings such as `characters`, `brightnessRange`, ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const sourceCanvas = document.createElement('canvas'); -sourceCanvas.width = 96; -sourceCanvas.height = 96; -const ctx = sourceCanvas.getContext('2d'); -let source; -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - source = t.createTexture(sourceCanvas); - source.characters(' .:-=+*#%@').cellColorMode('fixed').cellColor(4, 8, 16); -}); - -t.draw(() => { - t.background(4, 7, 18); - if (!ctx || !source) return; - - const hue = (t.frameCount * 2) % 360; - const gradient = ctx.createLinearGradient(0, 0, 96, 96); - gradient.addColorStop(0, `hsl(${hue}, 95%, 58%)`); - gradient.addColorStop(1, `hsl(${(hue + 130) % 360}, 90%, 45%)`); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 96); - ctx.fillStyle = '#ffffff'; - ctx.fillRect(18, 18, 60, 60); - ctx.fillStyle = '#111827'; - ctx.fillRect(30, 30, 36, 36); - - spin = (t.frameCount * 1.2) % 360; - t.perspective(58, 0.1, 4096); - t.camera(0, -8, 34, 0, 0, 0); - t.ambientLight(18, 20, 28); - t.pointLight([255, 230, 180], { x: 20, y: -18, z: 26 }); - t.texture(source); - t.rotateY(spin); - t.rotateX(18); - t.sphere(11); - t.noTexture(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TEXTURED GEOMETRY', x, y++, 100, 220, 255); - drawText('Canvas source samples the sphere.', x, y++, 140, 160, 190); - drawText('Brightness maps to glyphs.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/classes/Textmodifier/methods/torus.md b/api/textmode.js/classes/Textmodifier/methods/torus.md index 9136cf54..8c9e718d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/torus.md +++ b/api/textmode.js/classes/Textmodifier/methods/torus.md @@ -33,61 +33,5 @@ Draw a torus mesh primitive. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 40) % 360; - t.perspective(58, 0.1, 4096); - t.camera(18, -10, 42, 0, 0, 0); - t.ambientLight(24, 28, 38); - t.pointLight([255, 210, 140], { x: 18, y: -18, z: 28 }); - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.charColor(140, 220, 255); - t.cellColor(16, 24, 42); - t.torus(8, 2); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TORUS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 3D TORUS', x, y++, 100, 220, 255); - drawText('Major and tube radius define ring.', x, y++, 140, 160, 190); - drawText('Camera and light reveal depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md index 089d1f02..5c9d7a3a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md @@ -35,76 +35,5 @@ leaves the window. Treat this as an aborted touch and clean up any in-progress s ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.touchCancelled((data) => { - const touch = data?.touch || t.mouse; - addPulse('CANCELS', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TOUCHCANCELLED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TOUCH CANCEL', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CANCELS: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md index 6814f87a..cad28248 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md @@ -35,76 +35,5 @@ event. Use it to finalise state such as drawing strokes or completing gestures. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.touchEnded((data) => { - const touch = data?.touch || t.mouse; - addPulse('ENDS', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TOUCHENDED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TOUCH END', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ENDS: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md index 86588d12..5454552b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md @@ -35,76 +35,5 @@ The provided callback is invoked continuously while the browser reports move eve ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.touchMoved((data) => { - const touch = data?.touch || t.mouse; - addPulse('MOVES', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TOUCHMOVED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TOUCH MOVE', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('MOVES: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md index 31d165e6..618393e5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md @@ -36,76 +36,5 @@ more fingers on the canvas. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const pulses = []; -let count = 0; -let last = 'WAITING'; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function addPulse(label, x = 0, y = 0) { - count++; - last = label; - pulses.unshift({ label, x, y, life: 1 }); - if (pulses.length > 12) pulses.length = 12; -} - -t.touchStarted((data) => { - const touch = data?.touch || t.mouse; - addPulse('STARTS', touch?.x || 0, touch?.y || 0); -}); - -t.draw(() => { - t.background(6, 10, 22); - - for (let i = pulses.length - 1; i >= 0; i--) { - const p = pulses[i]; - p.life -= 0.02; - if (p.life <= 0) { - pulses.splice(i, 1); - continue; - } - t.push(); - t.translate(p.x, p.y - (1 - p.life) * 4); - t.char('*'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TOUCHSTARTED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TOUCH BEGIN', x, y++, 100, 220, 255); - drawText('Event updates compact state.', x, y++, 140, 160, 190); - drawText('Pulses show recent triggers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STARTS: ' + count, x, y++, 140, 255, 180); - drawText('LAST: ' + last.slice(0, 28), x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/translate.md b/api/textmode.js/classes/Textmodifier/methods/translate.md index 24df49a0..d50b9546 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translate.md +++ b/api/textmode.js/classes/Textmodifier/methods/translate.md @@ -39,58 +39,5 @@ All geometries are displaced by the specified amounts. Similar to p5.js translat ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let value = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.04; - value = Math.sin(time) * 12; - t.charColor(50, 60, 90); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - t.push(); - t.translate(value, Math.cos(time) * 5, 0); - t.char('#'); - t.charColor(140, 255, 180); - t.rect(6, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRANSLATE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MOVE ORIGIN', x, y++, 100, 220, 255); - drawText('Moves x, y, and z together.', x, y++, 140, 160, 190); - drawText('Grid cross shows original axes.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`X: ${value.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/translateX.md b/api/textmode.js/classes/Textmodifier/methods/translateX.md index 3ab5463f..8345d6c5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateX.md @@ -30,78 +30,7 @@ Current X-axis translation in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let y = top; y <= bottom; y++) { - const shiftX = Math.sin(tm * 1.8 + y * 0.2) * 8; - - for (let x = left; x <= right; x++) { - const wave = Math.sin((x + shiftX) * 0.25 + tm); - const norm = (wave + 1) * 0.5; - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.translate(0, y); - t.translateX(shiftX); - t.translate(x, 0); - t.charColor(Math.floor(100 + norm * 155), Math.floor(220 - norm * 60), Math.floor(255 - norm * 100)); - t.cellColor(Math.floor(8 + norm * 14), Math.floor(24 + norm * 16), Math.floor(40 + norm * 20)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.TRANSLATEX', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HORIZONTAL SINE WAVE MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('Shifts origin along X-axis independently', x, y++); - t.print('without affecting Y or Z coordinates.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('DISPLACEMENT: FULL-SCREEN X-AXIS WAVE', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -123,86 +52,5 @@ Translate subsequent shapes along the X axis. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let y = top; y <= bottom; y++) { - const shiftA = Math.sin(tm * 1.6 + y * 0.25) * 8; - const shiftB = -shiftA; - - for (let x = left; x <= right; x++) { - const waveA = Math.sin((x + shiftA) * 0.2 + tm); - const normA = (waveA + 1) * 0.5; - - const charKey = RAMP[Math.floor(normA * (RAMP.length - 1))]; - - t.push(); - t.translate(0, y); - t.translateX(shiftA); - t.translate(x, 0); - t.charColor(Math.floor(255 - normA * 80), Math.floor(140 + normA * 100), Math.floor(100 + normA * 120)); - t.cellColor(Math.floor(24 + normA * 14), Math.floor(10 + normA * 12), Math.floor(6 + normA * 10)); - t.char(charKey); - t.point(); - t.pop(); - - t.push(); - t.translate(0, y); - t.translateX(shiftB); - t.translate(x, 0); - t.charColor(Math.floor(100 + normA * 120), Math.floor(240 - normA * 80), Math.floor(180 + normA * 75)); - t.cellColor(Math.floor(6 + normA * 10), Math.floor(20 + normA * 14), Math.floor(12 + normA * 12)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.TRANSLATEX2', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: INTERLOCKING DNA WAVE CURTAIN', x, y++); - t.charColor(140, 160, 190); - t.print('Interlocking double-helix strands', x, y++); - t.print('oscillating horizontally across canvas.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('DISPLACEMENT: PHASED FULL-GRID X SHIFT', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/translateY.md b/api/textmode.js/classes/Textmodifier/methods/translateY.md index cd8cfa97..4110f87f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateY.md @@ -30,78 +30,7 @@ Current Y-axis translation in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let x = left; x <= right; x++) { - const shiftY = Math.sin(tm * 2 + x * 0.25) * 6; - - for (let y = top; y <= bottom; y++) { - const wave = Math.cos((y + shiftY) * 0.25 + tm); - const norm = (wave + 1) * 0.5; - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.translate(x, 0); - t.translateY(shiftY); - t.translate(0, y); - t.charColor(255, Math.floor(160 + norm * 95), Math.floor(80 + norm * 120)); - t.cellColor(Math.floor(28 + norm * 14), Math.floor(12 + norm * 12), Math.floor(6 + norm * 10)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.TRANSLATEY', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: EQUALIZER SEISMIC PISTON ARRAY', x, y++); - t.charColor(140, 160, 190); - t.print('Shifts origin along Y-axis independently', x, y++); - t.print('without affecting X or Z coordinates.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('DISPLACEMENT: FULL-SCREEN Y-AXIS PISTONS', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -123,75 +52,5 @@ Translate subsequent shapes along the Y axis. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let x = left; x <= right; x++) { - const dropY = ((tm * 12 + Math.sin(x * 0.4) * 15) % rows) - Math.floor(rows / 2); - - for (let y = top; y <= bottom; y++) { - const distToHead = Math.abs(y - dropY); - const norm = Math.max(0, 1 - distToHead / 8); - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.translate(x, 0); - t.translateY(dropY * 0.1); - t.translate(0, y); - t.charColor(Math.floor(60 + norm * 195), Math.floor(220 + norm * 35), Math.floor(180 - norm * 80)); - t.cellColor(Math.floor(4 + norm * 12), Math.floor(16 + norm * 20), Math.floor(24 + norm * 16)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.TRANSLATEY2', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: DIGITAL RAIN WATERFALL CASCADE', x, y++); - t.charColor(140, 160, 190); - t.print('Vertical offset streams cascading', x, y++); - t.print('downwards through coordinate space.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('DISPLACEMENT: CONTINUOUS Y RAIN STREAM', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/translateZ.md b/api/textmode.js/classes/Textmodifier/methods/translateZ.md index b0e43263..fef25392 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateZ.md @@ -30,76 +30,7 @@ Current Z-axis translation in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-=+*#%@'; - -t.draw(() => { - t.background(6, 10, 24); - const cols = t.grid.cols, - rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2), - right = left + cols - 1; - const top = -Math.floor(rows / 2), - bottom = top + rows - 1; - const tm = t.frameCount * 0.04; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const z = Math.sin(dist * 0.25 - tm * 3) * 16; - const norm = (z + 16) / 32; - - const charKey = RAMP[Math.floor(norm * (RAMP.length - 1))]; - - t.push(); - t.translateZ(z); - t.translate(x, y); - t.charColor(Math.floor(100 + norm * 155), Math.floor(220 - norm * 80), Math.floor(255 - norm * 120)); - t.cellColor(Math.floor(8 + norm * 16), Math.floor(20 + norm * 18), Math.floor(40 + norm * 20)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3, - x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODIFIER.TRANSLATEZ', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: 3D HYPER-TUNNEL TRAVEL', x, y++); - t.charColor(140, 160, 190); - t.print('Translates origin along Z-axis (depth)', x, y++); - t.print('demonstrating 3D perspective projection.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('DISPLACEMENT: FULL-GRID Z-AXIS WARP', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature @@ -121,56 +52,5 @@ Translate subsequent shapes along the Z axis. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - t.perspective(58, 0.1, 4096); - t.camera(0, 0, 48, 0, 0, 0); - const time = t.frameCount * 0.03; - for (let i = 0; i < 4; i++) { - t.push(); - t.translate((i - 1.5) * 7, 0, 0); - t.translateZ(Math.sin(time + i) * 18); - t.char('#'); - t.charColor(120 + i * 30, 220, 255 - i * 20); - t.box(4, 4, 4); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRANSLATEZ2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DEPTH MOTION', x, y++, 100, 220, 255); - drawText('Boxes move toward camera.', x, y++, 140, 160, 190); - drawText('Z changes perspective scale.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.translateZ(z)', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/triangle.md b/api/textmode.js/classes/Textmodifier/methods/triangle.md index 6a824ad4..b1951069 100644 --- a/api/textmode.js/classes/Textmodifier/methods/triangle.md +++ b/api/textmode.js/classes/Textmodifier/methods/triangle.md @@ -43,53 +43,5 @@ Draw a triangle with the current settings. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const time = t.frameCount * 0.03; - t.push(); - t.translate(8, 2); - t.rotateZ(Math.sin(time) * 18); - t.char('^'); - t.charColor(255, 210, 120); - t.cellColor(30, 20, 10); - t.triangle(-9, 6, 0, -7, 9, 6); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: THREE POINT SHAPE', x, y++, 100, 220, 255); - drawText('Uses three explicit vertices.', x, y++, 140, 160, 190); - drawText('Rotation shows the filled area.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('API: t.triangle(...)', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md index 64376e63..e870dbef 100644 --- a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md +++ b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md @@ -39,51 +39,5 @@ Current base-layer tileset-color mode when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let authored = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - authored = Math.floor(t.frameCount / 120) % 2 === 0; - t.useTileColors(authored); - t.char(65); - t.charColor(255, 210, 120); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.USETILECOLORS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TILE COLORS', x, y++, 100, 220, 255); - drawText('Toggles authored tile color.', x, y++, 140, 160, 190); - drawText('charColor handles recolor mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(authored ? 'MODE: AUTHORED' : 'MODE: RECOLOR', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/vertex.md b/api/textmode.js/classes/Textmodifier/methods/vertex.md index bb4f83d8..f45c9af3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/vertex.md +++ b/api/textmode.js/classes/Textmodifier/methods/vertex.md @@ -38,93 +38,5 @@ The current transform, character, color, and line state are captured for this ve ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let spin = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function pyramid(size, height) { - const half = size * 0.5; - const top = [0, -height * 0.55, 0]; - const baseY = height * 0.35; - const corners = [ - [-half, baseY, -half], - [half, baseY, -half], - [half, baseY, half], - [-half, baseY, half], - ]; - - t.beginShape(t.TRIANGLES); - for (let i = 0; i < corners.length; i++) { - const next = corners[(i + 1) % corners.length]; - const shade = 120 + i * 32; - t.charColor(shade, 220, 255); - t.vertex(top[0], top[1], top[2]); - t.vertex(corners[i][0], corners[i][1], corners[i][2]); - t.vertex(next[0], next[1], next[2]); - } - - t.charColor(255, 210, 120); - t.vertex(corners[0][0], corners[0][1], corners[0][2]); - t.vertex(corners[1][0], corners[1][1], corners[1][2]); - t.vertex(corners[2][0], corners[2][1], corners[2][2]); - t.vertex(corners[0][0], corners[0][1], corners[0][2]); - t.vertex(corners[2][0], corners[2][1], corners[2][2]); - t.vertex(corners[3][0], corners[3][1], corners[3][2]); - t.endShape(); -} - -t.draw(() => { - t.background(5, 8, 18); - const time = t.frameCount * 0.025; - spin = (time * 42) % 360; - - t.perspective(58, 0.1, 4096); - t.camera(18, -12, 44, 0, 0, 0); - t.ambientLight(18, 24, 34); - t.pointLight([255, 240, 180], { x: 18, y: -20, z: 30 }); - - t.push(); - t.translate(5, 1, 0); - t.rotateY(spin); - t.rotateX(18); - t.char('#'); - t.cellColor(10, 20, 38); - pyramid(14, 12); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BEGINSHAPE2', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CUSTOM 3D MESH', x, y++, 100, 220, 255); - drawText('vertex(x, y, z) builds faces.', x, y++, 140, 160, 190); - drawText('Camera rotation reveals depth.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`SPIN: ${spin.toFixed(1)}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/methods/windowResized.md b/api/textmode.js/classes/Textmodifier/methods/windowResized.md index a6f74e27..97ca9bd3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/windowResized.md +++ b/api/textmode.js/classes/Textmodifier/methods/windowResized.md @@ -32,53 +32,5 @@ Set the callback that runs after a window resize. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let resizes = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -window.addEventListener('resize', () => { - resizes++; -}); - -t.draw(() => { - t.background(6, 10, 22); - t.char('#'); - t.charColor(140, 220, 255); - t.rect(12, 5); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.WINDOWRESIZED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RESIZE CALLBACK', x, y++, 100, 220, 255); - drawText('windowResized keeps canvas fit.', x, y++, 140, 160, 190); - drawText('Browser resize updates count.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`RESIZES: ${resizes}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md index 17cacc62..c39110f4 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md @@ -26,79 +26,4 @@ that should get brighter as animated layers overlap. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_ADDITIVE; -const modeName = 'BLEND_ADDITIVE'; -const accent = [255, 100, 80]; -const base = [28, 80, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.78 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(4, 8, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.17 + y * 0.11 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : ':'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(2, 6, 16); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 16; i++) { - const angle = i * 22.5 + ring * 11 + t.frameCount * 1.6; - const radius = 4 + ring * 3.8 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '*' : '@'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 10, 12); - t.rect(3, 2 + (i % 2)); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_ADDITIVE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ADDITIVE LIGHT', x, y++, 100, 220, 255); - drawText('Overlaps grow brighter.', x, y++, 140, 160, 190); - drawText('Good for sparks and glow.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md index 4c32372c..be235293 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md @@ -26,79 +26,4 @@ shapes that should compress color toward black. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_COLOR_BURN; -const modeName = 'BLEND_COLOR_BURN'; -const accent = [120, 50, 70]; -const base = [220, 170, 110]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.034; - t.background(50, 34, 22); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.13 - y * 0.15 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '%' : '+'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(52, 28, 16); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 18 - t.frameCount * 1.2; - const radius = 5 + ring * 3.8 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '#' : 'X'); - t.charColor(...accent); - t.cellColor(24 + ring * 10, 5, 10 + ring * 6); - t.rect(4, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_COLOR_BURN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: BURN SHADOWS', x, y++, 100, 220, 255); - drawText('Color compresses darker.', x, y++, 140, 160, 190); - drawText('Motion leaves dense marks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md index 778a8aed..737b9037 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md @@ -26,79 +26,4 @@ should push quickly toward white. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_COLOR_DODGE; -const modeName = 'BLEND_COLOR_DODGE'; -const accent = [255, 245, 170]; -const base = [42, 80, 130]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.72 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.038; - t.background(4, 10, 24); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.15 + y * 0.14 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(3, 8, 20); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 19 + t.frameCount * 1.8; - const radius = 4 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '*' : '@'); - t.charColor(...accent); - t.cellColor(45 + ring * 22, 42 + ring * 16, 16); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_COLOR_DODGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DODGE FLARES', x, y++, 100, 220, 255); - drawText('Small marks bloom fast.', x, y++, 140, 160, 190); - drawText('Highlights push to white.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md index 37d32c92..0c637627 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md @@ -26,79 +26,4 @@ existing composition. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_DARKEN; -const modeName = 'BLEND_DARKEN'; -const accent = [90, 110, 170]; -const base = [220, 190, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.03; - t.background(46, 40, 25); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.16 - y * 0.1 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(48, 38, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 19 + t.frameCount; - const radius = 5 + ring * 3.8 + Math.cos(time + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time * 1.5 + i) * 2); - t.char(ring % 2 ? '%' : '#'); - t.charColor(...accent); - t.cellColor(10 + ring * 7, 12 + ring * 8, 30 + ring * 14); - t.rect(4, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_DARKEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DARKER CHANNELS', x, y++, 100, 220, 255); - drawText('Only darker color wins.', x, y++, 140, 160, 190); - drawText('Moving marks add shade.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md index ad202afc..ec4904fb 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md @@ -26,79 +26,4 @@ overlaps that reveal contrast where colors diverge. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_DIFFERENCE; -const modeName = 'BLEND_DIFFERENCE'; -const accent = [255, 255, 255]; -const base = [70, 180, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.9 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.036; - t.background(8, 16, 24); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.17 + y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '-'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(4, 12, 20); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 29 + t.frameCount * 1.5; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '@' : '#'); - t.charColor(...accent); - t.cellColor(70, 70, 70); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_DIFFERENCE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT BY DISTANCE', x, y++, 100, 220, 255); - drawText('Unlike colors spark edges.', x, y++, 140, 160, 190); - drawText('Overlaps flip the field.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md index d1d66b8e..2201ece3 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md @@ -26,79 +26,4 @@ overlays that should shift color without the full edge of difference. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_EXCLUSION; -const modeName = 'BLEND_EXCLUSION'; -const accent = [230, 230, 255]; -const base = [120, 100, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.033; - t.background(16, 14, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.16 - y * 0.13 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 32, base[2]); - t.cellColor(10, 8, 24); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 25 - t.frameCount * 1.25; - const radius = 5 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(45 + ring * 12, 45 + ring * 12, 68); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_EXCLUSION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOFT INVERSION', x, y++, 100, 220, 255); - drawText('Difference with less bite.', x, y++, 140, 160, 190); - drawText('Color shifts stay muted.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md index 43170f0a..a8692632 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md @@ -26,79 +26,4 @@ marks that should strongly reshape contrast. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_HARD_LIGHT; -const modeName = 'BLEND_HARD_LIGHT'; -const accent = [255, 220, 70]; -const base = [65, 75, 150]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(10, 12, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.18 - y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '#' : ':'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(8, 8, 24); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 27 - t.frameCount * 1.6; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.4; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? 'X' : '#'); - t.charColor(...accent); - t.cellColor(45 + ring * 20, 38 + ring * 12, 6); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_HARD_LIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HARD CONTRAST', x, y++, 100, 220, 255); - drawText('The top layer drives punch.', x, y++, 140, 160, 190); - drawText('Edges become more graphic.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md index 1d6cb99b..795681db 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md @@ -26,79 +26,4 @@ existing composition. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_LIGHTEN; -const modeName = 'BLEND_LIGHTEN'; -const accent = [255, 230, 130]; -const base = [40, 70, 105]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.034; - t.background(8, 15, 28); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.13 + y * 0.18 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? ':' : '.'); - t.charColor(base[0], base[1] + wave * 25, base[2]); - t.cellColor(5, 10, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 13 - t.frameCount * 1.1; - const radius = 4 + ring * 4 + Math.sin(time + i) * 2.2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time * 1.6 + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(45 + ring * 15, 42 + ring * 10, 18); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_LIGHTEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LIGHTER CHANNELS', x, y++, 100, 220, 255); - drawText('Only brighter color wins.', x, y++, 140, 160, 190); - drawText('Moving marks reveal light.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md index 059dab5f..9414abe9 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md @@ -26,79 +26,4 @@ shadow-like patterns that preserve underlying contrast. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_MULTIPLY; -const modeName = 'BLEND_MULTIPLY'; -const accent = [130, 180, 255]; -const base = [220, 150, 90]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.032; - t.background(42, 30, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.12 - y * 0.16 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '%' : '+'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(50, 28, 12); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 20; i++) { - const angle = i * 18 + ring * 14 - t.frameCount * 1.1; - const radius = 6 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + ring) * 2); - t.char(ring % 2 ? 'X' : '#'); - t.charColor(...accent); - t.cellColor(12, 25 + ring * 20, 58 + ring * 12); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_MULTIPLY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MULTIPLY SHADE', x, y++, 100, 220, 255); - drawText('Overlap darkens the base.', x, y++, 140, 160, 190); - drawText('Color stays tied to below.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md index a763dbdd..b548338c 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md @@ -26,80 +26,4 @@ controlling how much of the layer covers the layers below it. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_NORMAL; -const modeName = 'BLEND_NORMAL'; -const accent = [250, 180, 90]; -const base = [35, 70, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 10, 22); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.18 + y * 0.13 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0] + wave * 30, base[1] + 20, base[2]); - t.cellColor(4, 8, 18); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 17 + t.frameCount * (1.2 + ring * 0.2); - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.rotateZ(-angle * 0.5); - t.char(ring % 2 ? '@' : '#'); - t.charColor(...accent); - t.cellColor(20 + ring * 18, 16, 32 + ring * 12); - t.rect(3 + (i % 2), 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_NORMAL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: NORMAL BLEND', x, y++, 100, 220, 255); - drawText('Animated layer covers below.', x, y++, 140, 160, 190); - drawText('Opacity controls the mix.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md index a1906c33..7226d4e3 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md @@ -26,79 +26,4 @@ highlights in one pass. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_OVERLAY; -const modeName = 'BLEND_OVERLAY'; -const accent = [255, 90, 190]; -const base = [80, 125, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.83 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.037; - t.background(10, 18, 32); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.14 + y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : '-'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(8, 14, 26); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 21 + t.frameCount * 1.35; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '@' : '%'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 10, 42 + ring * 12); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_OVERLAY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONTRAST BOOST', x, y++, 100, 220, 255); - drawText('Dark stays deep, light lifts.', x, y++, 140, 160, 190); - drawText('Good for graphic masks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md index a5bbe48d..93d01621 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md @@ -26,79 +26,4 @@ areas while preserving highlight detail. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SCREEN; -const modeName = 'BLEND_SCREEN'; -const accent = [100, 220, 255]; -const base = [85, 45, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.8 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.036; - t.background(12, 8, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.2 + y * 0.08 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(8, 4, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 23 + t.frameCount * 1.3; - const radius = 6 + ring * 3.5 + Math.sin(time + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time * 1.4 + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(5, 30 + ring * 10, 45 + ring * 20); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SCREEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCREEN LIGHT', x, y++, 100, 220, 255); - drawText('Dark areas lift upward.', x, y++, 140, 160, 190); - drawText('Highlights stay open.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md index f31e0cdc..b6f9af80 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md @@ -26,79 +26,4 @@ animated texture that should stay subtle. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SOFT_LIGHT; -const modeName = 'BLEND_SOFT_LIGHT'; -const accent = [255, 170, 150]; -const base = [70, 120, 160]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.029; - t.background(12, 20, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.12 + y * 0.15 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(8, 14, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 16 + t.frameCount * 0.9; - const radius = 5 + ring * 3.5 + Math.sin(time + i) * 1.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '+' : '*'); - t.charColor(...accent); - t.cellColor(28 + ring * 14, 20 + ring * 10, 30); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SOFT_LIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOFT CONTRAST', x, y++, 100, 220, 255); - drawText('Texture changes gently.', x, y++, 140, 160, 190); - drawText('Useful for atmosphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md index 17bcf0e9..337906a9 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md @@ -26,79 +26,4 @@ that remove brightness from the composite. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SUBTRACT; -const modeName = 'BLEND_SUBTRACT'; -const accent = [180, 230, 255]; -const base = [210, 120, 70]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.033; - t.background(48, 28, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.11 + y * 0.19 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : '+'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(55, 24, 10); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 15 - t.frameCount * 1.4; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.8; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '/' : '\\'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 45 + ring * 12, 58); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SUBTRACT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUBTRACT CUTS', x, y++, 100, 220, 255); - drawText('The top layer removes light.', x, y++, 140, 160, 190); - drawText('Bright marks carve paths.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/LINES.md b/api/textmode.js/classes/Textmodifier/properties/LINES.md index b0aca79a..c163e2ee 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINES.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINES.md @@ -25,59 +25,5 @@ geometry where every two vertices form a separate edge. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINES; -const modeName = 'LINES'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 8, 22); - t.lineWeight(0.7); - t.beginShape(mode); - for (let i = 0; i < 30; i++) { - const a = i * 12 + t.frameCount * 0.9; - const r1 = 4 + Math.sin(time + i) * 2; - const r2 = 13 + Math.cos(time * 1.7 + i) * 3; - t.char(i % 2 ? '/' : '\\'); - t.charColor(120 + i * 4, 240 - i * 3, 210); - t.vertex(Math.cos(a) * r1, Math.sin(a) * r1); - t.vertex(Math.cos(a + 30) * r2, Math.sin(a + 30) * r2); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PAIRED SEGMENTS', x, y++, 100, 220, 255); - drawText('Every two vertices connect.', x, y++, 140, 160, 190); - drawText('Each pair stays separate.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md index 50805557..1fd4ee7b 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md @@ -25,58 +25,5 @@ the last vertex should connect back to the first. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINE_LOOP; -const modeName = 'LINE_LOOP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(7, 10, 24); - t.lineWeight(0.7); - t.beginShape(mode); - for (let i = 0; i < 64; i++) { - const p = i / 64; - const a = p * Math.PI * 2; - const r = 10 + Math.sin(a * 5 + time * 2) * 2 + Math.cos(a * 3 - time) * 1.5; - t.char(i % 5 === 0 ? '#' : '+'); - t.charColor(120 + Math.sin(a) * 80, 210, 180 + Math.cos(a) * 60); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINE_LOOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLOSED OUTLINE', x, y++, 100, 220, 255); - drawText('Last vertex returns to first.', x, y++, 140, 160, 190); - drawText('Good for orbiting contours.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md index 6b1a1aec..ad6a314b 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md @@ -25,58 +25,5 @@ paths that should not automatically close. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINE_STRIP; -const modeName = 'LINE_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(5, 12, 25); - t.lineWeight(0.8); - t.beginShape(mode); - for (let i = 0; i < 70; i++) { - const p = i / 69; - const x = -22 + p * 44; - const y = Math.sin(p * Math.PI * 6 + time * 2) * 5 + Math.sin(p * 19 - time) * 2; - t.char(i % 4 === 0 ? '@' : '~'); - t.charColor(80 + p * 160, 170 + Math.sin(p * 7) * 70, 255); - t.vertex(x, y); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINE_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: OPEN CONTINUOUS PATH', x, y++, 100, 220, 255); - drawText('Consecutive vertices connect.', x, y++, 140, 160, 190); - drawText('The ends remain open.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/POINTS.md b/api/textmode.js/classes/Textmodifier/properties/POINTS.md index abae038a..251258db 100644 --- a/api/textmode.js/classes/Textmodifier/properties/POINTS.md +++ b/api/textmode.js/classes/Textmodifier/properties/POINTS.md @@ -25,57 +25,5 @@ where every vertex is an independent mark. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.POINTS; -const modeName = 'POINTS'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(6, 10, 24); - t.beginShape(mode); - for (let i = 0; i < 96; i++) { - const a = i * 13.7 + t.frameCount * 1.4; - const r = 2 + i * 0.12 + Math.sin(time * 2 + i) * 1.2; - t.char(i % 3 === 0 ? '*' : '.'); - t.charColor(90 + i, 180 + Math.sin(i) * 50, 255); - t.cellColor(4, 12 + (i % 6) * 5, 30); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POINTS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VERTEX PARTICLES', x, y++, 100, 220, 255); - drawText('Each vertex becomes a point.', x, y++, 140, 160, 190); - drawText('No edges connect the marks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/QUADS.md b/api/textmode.js/classes/Textmodifier/properties/QUADS.md index ff60cb84..db89bd9c 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUADS.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUADS.md @@ -25,63 +25,5 @@ every four vertices define a separate four-sided patch. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.QUADS; -const modeName = 'QUADS'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(6, 10, 20); - t.beginShape(mode); - for (let gy = -2; gy <= 2; gy++) { - for (let gx = -4; gx <= 4; gx++) { - const cx = gx * 4 + Math.sin(time + gy) * 1.5; - const cy = gy * 4 + Math.cos(time + gx) * 1.5; - const s = 1.4 + Math.sin(time * 2 + gx + gy) * 0.5; - t.char((gx + gy) % 2 ? '#' : '+'); - t.charColor(120 + gx * 14, 190 + gy * 12, 250); - t.cellColor(12 + gx * 3, 22 + gy * 6, 45); - t.vertex(cx - s, cy - s); - t.vertex(cx + s, cy - s); - t.vertex(cx + s, cy + s); - t.vertex(cx - s, cy + s); - } - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.QUADS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FOUR VERTEX PATCHES', x, y++, 100, 220, 255); - drawText('Every four vertices fill.', x, y++, 140, 160, 190); - drawText('Each cell is independent.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md index 091f09d1..15e6aa9f 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md @@ -25,60 +25,5 @@ pair of vertices extends the next four-sided segment. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.QUAD_STRIP; -const modeName = 'QUAD_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(8, 8, 24); - t.beginShape(mode); - for (let i = 0; i < 28; i++) { - const p = i / 27; - const x = -20 + p * 40; - const y = Math.sin(p * Math.PI * 4 + time * 2) * 5; - const width = 2 + Math.cos(time + i) * 0.8; - t.char(i % 2 ? '=' : '#'); - t.charColor(255 - p * 80, 140 + p * 90, 210); - t.cellColor(40 + p * 30, 16, 45 + p * 40); - t.vertex(x, y - width); - t.vertex(x, y + width); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.QUAD_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONNECTED QUAD BAND', x, y++, 100, 220, 255); - drawText('Each pair extends the strip.', x, y++, 140, 160, 190); - drawText('Good for thick flowing paths.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md index c127da26..1c301f72 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md @@ -25,61 +25,5 @@ each triangle controls its own three corners. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLES; -const modeName = 'TRIANGLES'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 8, 20); - t.beginShape(mode); - for (let i = 0; i < 18; i++) { - const a = i * 20 + t.frameCount; - const cx = Math.cos(a) * (5 + (i % 3) * 4); - const cy = Math.sin(a) * (5 + (i % 4) * 2); - const size = 2 + Math.sin(time + i) * 0.8; - t.char(i % 2 ? '^' : '#'); - t.charColor(250, 110 + i * 6, 150 + i * 3); - t.cellColor(40 + i * 4, 10, 25); - t.vertex(cx + Math.cos(a) * size, cy + Math.sin(a) * size); - t.vertex(cx + Math.cos(a + 120) * size, cy + Math.sin(a + 120) * size); - t.vertex(cx + Math.cos(a + 240) * size, cy + Math.sin(a + 240) * size); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INDEPENDENT FACETS', x, y++, 100, 220, 255); - drawText('Every three vertices fill.', x, y++, 140, 160, 190); - drawText('Each triangle stands alone.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md index b8611658..07e89a30 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md @@ -25,62 +25,5 @@ expanding from a shared center. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLE_FAN; -const modeName = 'TRIANGLE_FAN'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(10, 8, 24); - t.beginShape(mode); - t.char('@'); - t.charColor(255, 245, 180); - t.cellColor(65, 40, 20); - t.vertex(0, 0); - for (let i = 0; i <= 48; i++) { - const p = i / 48; - const a = p * Math.PI * 2 + time; - const r = 12 + Math.sin(a * 6 - time * 3) * 2; - t.char(i % 3 ? '*' : '#'); - t.charColor(255, 130 + Math.sin(a) * 70, 90 + Math.cos(a) * 60); - t.cellColor(55 + Math.sin(a) * 20, 18, 12); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLE_FAN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHARED CENTER', x, y++, 100, 220, 255); - drawText('Every triangle uses vertex 1.', x, y++, 140, 160, 190); - drawText('Great for radial bursts.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md index 3b109ea8..323b3d81 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md @@ -25,59 +25,5 @@ built from a single alternating vertex sequence. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLE_STRIP; -const modeName = 'TRIANGLE_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(5, 12, 26); - t.beginShape(mode); - for (let i = 0; i < 42; i++) { - const p = i / 41; - const x = -20 + p * 40; - const wave = Math.sin(p * Math.PI * 5 + time * 2) * 4; - const side = i % 2 === 0 ? -2.5 : 2.5; - t.char(i % 2 === 0 ? '/' : '\\'); - t.charColor(100 + p * 120, 240 - p * 70, 255); - t.cellColor(8, 28 + p * 40, 45 + p * 70); - t.vertex(x, wave + side); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLE_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONNECTED RIBBON', x, y++, 100, 220, 255); - drawText('Each new vertex adds a face.', x, y++, 140, 160, 190); - drawText('Alternating sides make width.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md index 575965e8..1fe996fa 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md @@ -22,77 +22,5 @@ Physical screen height in pixels. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let displayH = 0; -let ratio = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(8, 9, 20); - displayH = t.displayHeight; - ratio = t.windowHeight / Math.max(1, displayH); - const full = 18; - const visible = Math.round(t.constrain(t.map(ratio, 0, 1, 3, full), 3, full)); - - drawBand(-8, 0, 1, full + 2, 70, 135, 185); - drawBand(8, 0, 1, full + 2, 70, 135, 185); - drawBand(0, -full / 2 - 1, 17, 1, 42, 58, 88); - drawBand(0, full / 2 + 1, 17, 1, 42, 58, 88); - drawBand(0, full / 2 - visible / 2, 11, visible, 62, 120, 165); - - for (let i = 0; i <= full; i += 2) { - const y = full / 2 - i; - const glow = i <= visible; - t.push(); - t.translate(Math.cos(t.frameCount * 0.04 + i) * 4, y); - t.char(glow ? '*' : '.'); - t.charColor(glow ? 255 : 75, glow ? 210 : 95, glow ? 125 : 130); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DISPLAYHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCREEN HEIGHT', x, y++, 100, 220, 255); - drawText('displayHeight reads screen.height.', x, y++, 140, 160, 190); - drawText('Window height is shown inside it.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DISPLAY: ${displayH} PX`, x, y++, 255, 200, 100); - drawText(`WINDOW: ${(ratio * 100).toFixed(0)}%`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md index 5c0dbbcf..5116f67e 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md @@ -22,77 +22,5 @@ Physical screen width in pixels. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let displayW = 0; -let ratio = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(7, 10, 18); - displayW = t.displayWidth; - ratio = t.windowWidth / Math.max(1, displayW); - const full = 30; - const visible = Math.round(t.constrain(t.map(ratio, 0, 1, 3, full), 3, full)); - - drawBand(0, -6, full + 4, 1, 42, 58, 88); - drawBand(0, 6, full + 4, 1, 42, 58, 88); - drawBand(-full / 2 - 2, 0, 1, 13, 70, 135, 185); - drawBand(full / 2 + 2, 0, 1, 13, 70, 135, 185); - drawBand(-full / 2 + visible / 2, 0, visible, 7, 65, 125, 170); - - for (let i = 0; i <= full; i += 3) { - const x = -full / 2 + i; - const glow = i <= visible; - t.push(); - t.translate(x, Math.sin(t.frameCount * 0.04 + i) * 2); - t.char(glow ? '@' : '.'); - t.charColor(glow ? 255 : 80, glow ? 205 : 95, glow ? 120 : 125); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.DISPLAYWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCREEN WIDTH', x, y++, 100, 220, 255); - drawText('displayWidth reads screen.width.', x, y++, 140, 160, 190); - drawText('Window width is shown inside it.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DISPLAY: ${displayW} PX`, x, y++, 255, 200, 100); - drawText(`WINDOW: ${(ratio * 100).toFixed(0)}%`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/gamepads.md b/api/textmode.js/classes/Textmodifier/properties/gamepads.md index 6825c12d..179f48de 100644 --- a/api/textmode.js/classes/Textmodifier/properties/gamepads.md +++ b/api/textmode.js/classes/Textmodifier/properties/gamepads.md @@ -26,54 +26,5 @@ it does not contain sparse `null` holes for disconnected slots. Use ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 6, 12); - const count = Math.max(1, t.gamepads.length); - for (let i = 0; i < 16; i++) { - t.push(); - const angle = (i / 16) * Math.PI * 2 + t.frameCount * 0.03; - t.translate(Math.cos(angle) * (6 + count), Math.sin(angle) * 4); - t.char(t.gamepads.length ? '@' : '.'); - t.charColor(80 + i * 8, 180, 255); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODIFIER.GAMEPADS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GAMEPAD INPUT', x, y++, 100, 220, 255); - drawText('Works with browser pads.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`PADS: ${t.gamepads.length}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md index 6dc475f6..710f1dc7 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md @@ -22,87 +22,5 @@ Last key pressed, or `null` before any key press. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 18, 22); - - const keyStr = String(t.lastKeyPressed || 'NONE').toUpperCase(); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - - for (let y = -hh; y <= hh; y += 3) { - for (let x = -hw; x <= hw; x += 3) { - const wave = (Math.sin(x * 0.1 + tm) + Math.cos(y * 0.1 - tm)) * 0.5; - if (wave > 0.5) { - t.push(); - t.translate(x, y); - t.charColor(10, 36, 42); - t.char(wave > 0.8 ? '#' : '*'); - t.point(); - t.pop(); - } - } - } - - const pedW = 16, - pedH = 7; - const px = -Math.floor(pedW / 2), - py = -Math.floor(pedH / 2); - - for (let cy = 0; cy < pedH; cy++) { - for (let cx = 0; cx < pedW; cx++) { - const isBorder = cx === 0 || cx === pedW - 1 || cy === 0 || cy === pedH - 1; - t.push(); - t.translate(px + cx, py + cy); - t.cellColor(10, 36, 45); - if (isBorder) { - t.charColor(0, 229, 255); - const isCorner = (cy === 0 || cy === pedH - 1) && (cx === 0 || cx === pedW - 1); - t.char(isCorner ? '+' : cy === 0 || cy === pedH - 1 ? '=' : '|'); - } else { - t.char(' '); - } - t.point(); - t.pop(); - } - } - - t.push(); - t.printAlign('center', 'middle'); - t.charColor(255, 183, 0); - t.print(keyStr.slice(0, 12), 0, 0); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const keyStr = String(t.lastKeyPressed || 'NONE'); - - drawText('TEXTMODIFIER.LASTKEYPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PERSISTENT LAST KEY STATE', x, y++, 100, 220, 255); - drawText('Reads last pressed key property.', x, y++, 140, 160, 190); - drawText('Persists until next key is pressed.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('MEMORY VAULT KEY: ' + keyStr, x, y++, 140, 255, 180); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md index feae623a..de56d2a8 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md @@ -22,89 +22,5 @@ Last key released, or `null` before any key release. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 24); - - const keyStr = String(t.lastKeyReleased || 'NONE').toUpperCase(); - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y * 1.3), - echo = (d * 0.25 - tm) % 1.0; - const val = echo < 0 ? echo + 1.0 : echo; - if (val < 0.25) { - const int = 1 - val / 0.25; - t.push(); - t.translate(x, y); - t.charColor(Math.floor(157 + int * 60), Math.floor(78 + int * 90), 223); - t.char(d < 5 ? 'o' : d < 12 ? '*' : '.'); - t.point(); - t.pop(); - } - } - } - - const pedW = 16, - pedH = 5, - px = -8, - py = -2; - for (let cy = 0; cy < pedH; cy++) { - for (let cx = 0; cx < pedW; cx++) { - const isBorder = cx === 0 || cx === pedW - 1 || cy === 0 || cy === pedH - 1; - t.push(); - t.translate(px + cx, py + cy); - t.cellColor(24, 15, 45); - if (isBorder) { - t.charColor(224, 170, 255); - const isCorner = (cy === 0 || cy === pedH - 1) && (cx === 0 || cx === pedW - 1); - t.char(isCorner ? '+' : cy === 0 || cy === pedH - 1 ? '=' : '|'); - } else { - t.char(' '); - } - t.point(); - t.pop(); - } - } - - t.push(); - t.printAlign('center', 'middle'); - t.charColor(255, 204, 255); - t.print(keyStr.slice(0, 12), 0, 0); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const keyStr = String(t.lastKeyReleased || 'NONE'); - - drawText('TEXTMODIFIER.LASTKEYRELEASED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PERSISTENT LAST UP-STROKE', x, y++, 100, 220, 255); - drawText('Reads last released key property.', x, y++, 140, 160, 190); - drawText('Persists until next key is released.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('LAST RELEASED KEY: ' + keyStr, x, y++, 140, 255, 180); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/modifierState.md b/api/textmode.js/classes/Textmodifier/properties/modifierState.md index 3f0bebb6..914fda52 100644 --- a/api/textmode.js/classes/Textmodifier/properties/modifierState.md +++ b/api/textmode.js/classes/Textmodifier/properties/modifierState.md @@ -29,57 +29,5 @@ Current modifier key state. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let active = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - const m = t.modifierState; - active = [m.shift, m.ctrl, m.alt, m.meta].filter(Boolean).length; - ['SHIFT', 'CTRL', 'ALT', 'META'].forEach((name, i) => { - const on = [m.shift, m.ctrl, m.alt, m.meta][i]; - t.push(); - t.translate((i - 1.5) * 7, 0); - t.char(on ? '#' : '.'); - t.charColor(on ? 140 : 80, on ? 255 : 90, 180); - t.rect(5, 3); - t.pop(); - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MODIFIERSTATE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MODIFIER KEYS', x, y++, 100, 220, 255); - drawText('Tracks Shift/Ctrl/Alt/Meta.', x, y++, 140, 160, 190); - drawText('Hold keys to light panels.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ACTIVE: ${active}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/mouse.md b/api/textmode.js/classes/Textmodifier/properties/mouse.md index 18ba31a5..1399712f 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouse.md @@ -33,65 +33,5 @@ it returns `{ x: Number.NEGATIVE_INFINITY, y: Number.NEGATIVE_INFINITY }`. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let mx = 0; -let my = 0; -let inside = false; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - mx = t.mouse.x; - my = t.mouse.y; - inside = mx !== Number.NEGATIVE_INFINITY; - t.charColor(50, 60, 90); - t.char('.'); - t.line(-18, 0, 18, 0); - t.line(0, -10, 0, 10); - if (inside) { - t.push(); - t.translate(mx, my); - t.char('+'); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.MOUSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POINTER POSITION', x, y++, 100, 220, 255); - drawText('Reads current mouse cell position.', x, y++, 140, 160, 190); - drawText('Outside canvas returns infinity.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(inside ? 'INSIDE: TRUE' : 'INSIDE: FALSE', x, y++, 140, 255, 180); - drawText(`X: ${mx}`, x, y++, 180, 200, 220); - drawText(`Y: ${my}`, x, y++, 180, 200, 220); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md index e873ca32..74fe60c4 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md @@ -26,90 +26,5 @@ starts. Use it inside `draw()` for polling-style interactions. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const RAMP = '+xX#░▒▓█'; -const labelLayer = t.layers.add(); -let pressure = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 5, 10); - const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; - pressure += ((isHeld ? 1.0 : 0.0) - pressure) * 0.12; - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03, - mx = t.mouse.x, - my = t.mouse.y; - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const wave = (Math.sin(x * 0.12 + tm) + Math.cos(y * 0.12 - tm)) * 0.5 + 0.5; - let dispX = x, - dispY = y, - pullFactor = 0; - if (t.mouse.x !== Number.NEGATIVE_INFINITY) { - const dist = Math.hypot(x - mx, y - my); - if (dist < 22) { - pullFactor = Math.pow(1 - dist / 22, 2) * pressure; - dispX = x - (x - mx) * pullFactor * 0.45; - dispY = y - (y - my) * pullFactor * 0.45; - } - } - const intensity = Math.min(1, wave * 0.4 + pullFactor * 0.85); - if (intensity > 0.08) { - const charIdx = Math.min(RAMP.length - 1, Math.floor(intensity * RAMP.length)); - const rx = Math.round(dispX), - ry = Math.round(dispY); - if (rx >= -hw && rx <= hw && ry >= -hh && ry <= hh) { - t.push(); - t.translate(rx, ry); - if (pullFactor > 0.5) { - const h = (pullFactor - 0.5) / 0.5; - t.charColor(255, Math.floor(140 + h * 105), Math.floor(h * 230)); - t.cellColor(Math.floor(120 * h), Math.floor(30 * h), 0); - } else if (pullFactor > 0.15) { - const h = (pullFactor - 0.15) / 0.35; - t.charColor(Math.floor(160 + h * 95), Math.floor(70 + h * 70), Math.floor(30 - h * 30)); - } else { - const b = intensity; - t.charColor(Math.floor(28 + b * 22), Math.floor(45 + b * 37), Math.floor(90 + b * 78)); - } - t.char(RAMP[charIdx]); - t.point(); - t.pop(); - } - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isHeld = t.mouseIsPressed && t.mouse.x !== Number.NEGATIVE_INFINITY; - drawText('TEXTMODIFIER.MOUSEISPRESSED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SYNCHRONOUS HOLD STATE', x, y++, 100, 220, 255); - drawText('Evaluates boolean state every frame.', x, y++, 140, 160, 190); - drawText('Holding mouse implodes lattice core.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('MOUSE IS PRESSED: ' + (isHeld ? 'TRUE' : 'FALSE'), x, y++, 140, 255, 180); - drawText('PRESSURE INTENSITY: ' + Math.floor(pressure * 100) + '%', x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/movedX.md b/api/textmode.js/classes/Textmodifier/properties/movedX.md index 8b3bc2a7..e0822d32 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedX.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedX.md @@ -25,97 +25,5 @@ stop being meaningful and relative movement becomes the primary input signal. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let rotX = 0, - rotY = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (document.pointerLockElement === t.canvas) t.exitPointerLock(); - else t.requestPointerLock(); -}); - -t.draw(() => { - t.background(5, 8, 10); - const isLocked = document.pointerLockElement === t.canvas; - - if (isLocked) { - rotX += t.movedX * 0.35; - rotY += t.movedY * 0.35; - } else { - rotX += 0.25; - } - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const rad = Math.floor(Math.min(hw, hh) * 0.65); - const angleOffset = (rotX * 0.05) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y * 1.4); - const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; - - let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; - let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); - let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; - - if (isRing || isAxis || isTick) { - t.push(); - t.translate(x, y); - - if (isLocked) { - if (d < 3) { - t.charColor(255, 51, 51); - t.cellColor(90, 0, 0); - t.char('+'); - } else if (isTick) { - t.charColor(255, 200, 0); - t.char('#'); - } else { - t.charColor(255, 153, 0); - t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); - } - } else { - t.charColor(68, 85, 102); - t.char(isAxis ? '+' : '.'); - } - - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isLocked = document.pointerLockElement === t.canvas; - - drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); - drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); - drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); - drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); - drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/movedY.md b/api/textmode.js/classes/Textmodifier/properties/movedY.md index 822e64a1..8dea57cd 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedY.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedY.md @@ -25,97 +25,5 @@ stop being meaningful and relative movement becomes the primary input signal. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); -let rotX = 0, - rotY = 0; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.mouseClicked(() => { - if (document.pointerLockElement === t.canvas) t.exitPointerLock(); - else t.requestPointerLock(); -}); - -t.draw(() => { - t.background(5, 8, 10); - const isLocked = document.pointerLockElement === t.canvas; - - if (isLocked) { - rotX += t.movedX * 0.35; - rotY += t.movedY * 0.35; - } else { - rotX += 0.25; - } - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2); - const rad = Math.floor(Math.min(hw, hh) * 0.65); - const angleOffset = (rotX * 0.05) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const d = Math.hypot(x, y * 1.4); - const cellAngle = Math.atan2(y * 1.4, x) + Math.PI; - - let isRing = Math.abs(d - rad) < 0.8 || Math.abs(d - rad * 0.5) < 0.8; - let isAxis = (x === 0 && Math.abs(y) <= rad + 2) || (y === 0 && Math.abs(x) <= rad + 2); - let isTick = isRing && Math.abs((cellAngle + angleOffset) % (Math.PI / 4)) < 0.08; - - if (isRing || isAxis || isTick) { - t.push(); - t.translate(x, y); - - if (isLocked) { - if (d < 3) { - t.charColor(255, 51, 51); - t.cellColor(90, 0, 0); - t.char('+'); - } else if (isTick) { - t.charColor(255, 200, 0); - t.char('#'); - } else { - t.charColor(255, 153, 0); - t.char(isAxis ? (x === 0 ? '|' : '-') : '*'); - } - } else { - t.charColor(68, 85, 102); - t.char(isAxis ? '+' : '.'); - } - - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isLocked = document.pointerLockElement === t.canvas; - - drawText('TEXTMODIFIER.REQUESTPOINTERLOCK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: 360 DEGREE POINTER LOCK', x, y++, 100, 220, 255); - drawText('Click canvas to toggle pointer lock.', x, y++, 140, 160, 190); - drawText('Captures unconstrained movedX/movedY.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('POINTER LOCK: ' + (isLocked ? 'LOCKED' : 'UNLOCKED'), x, y++, 140, 255, 180); - drawText('ACCUMULATED ROTATION X: ' + rotX.toFixed(1), x, y++, 180, 200, 220); - drawText('ACCUMULATED ROTATION Y: ' + rotY.toFixed(1), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/pmouse.md b/api/textmode.js/classes/Textmodifier/properties/pmouse.md index ea18eb11..d1691008 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pmouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/pmouse.md @@ -33,101 +33,5 @@ If no previous frame position is available yet, it returns ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(), - trail = []; - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(10, 14, 23); - const mx = t.mouse.x, - my = t.mouse.y, - px = t.pmouse.x, - py = t.pmouse.y; - const isInside = mx !== Number.NEGATIVE_INFINITY && px !== Number.NEGATIVE_INFINITY; - - if (isInside) { - const spd = Math.hypot(mx - px, my - py); - trail.unshift({ x: mx, y: my, speed: spd, life: 1.0 }); - if (trail.length > 35) trail.length = 35; - } - - const hw = Math.floor(t.grid.cols / 2), - hh = Math.floor(t.grid.rows / 2), - tm = t.frameCount * 0.02; - - for (let y = -hh; y <= hh; y += 3) { - for (let x = -hw; x <= hw; x += 3) { - const a = Math.sin(x * 0.08 + tm) + Math.cos(y * 0.08 - tm); - t.push(); - t.translate(x, y); - t.charColor(24, 35, 60); - t.char(a > 0.8 ? '/' : a > 0 ? '|' : a > -0.8 ? '\\' : '-'); - t.point(); - t.pop(); - } - } - - for (let i = trail.length - 1; i >= 0; i--) { - const node = trail[i]; - if ((node.life -= 0.025) <= 0) { - trail.splice(i, 1); - continue; - } - const nx = Math.round(node.x), - ny = Math.round(node.y); - if (nx >= -hw && nx <= hw && ny >= -hh && ny <= hh) { - t.push(); - t.translate(nx, ny); - if (node.speed > 3.0) { - t.charColor(255, 255, 255); - t.cellColor(0, 140, 200); - t.char('█'); - } else if (node.speed > 1.0) { - t.charColor(0, 212, 255); - t.cellColor(0, 50, 80); - t.char('▓'); - } else { - t.charColor(60, 130, 190); - t.char('▒'); - } - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const mx = t.mouse.x, - my = t.mouse.y, - px = t.pmouse.x, - py = t.pmouse.y; - const isInside = mx !== Number.NEGATIVE_INFINITY; - - drawText('TEXTMODIFIER.PMOUSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PREVIOUS POINTER VECTOR', x, y++, 100, 220, 255); - drawText('Reads previous frame coordinates.', x, y++, 140, 160, 190); - drawText('Calculates motion speed & vector stroke.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CURRENT POS: ' + (isInside ? `(${mx}, ${my})` : 'OUTSIDE'), x, y++, 140, 255, 180); - drawText('PREVIOUS POS: ' + (isInside ? `(${px}, ${py})` : 'OUTSIDE'), x, y++, 180, 200, 220); - drawText('MOTION SPEED: ' + (isInside ? Math.hypot(mx - px, my - py).toFixed(2) : '0.00'), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md index 3db66763..94ccb1f9 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md +++ b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md @@ -22,96 +22,5 @@ Keys currently being held down. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const labelLayer = t.layers.add(); - -function drawText(txt, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(txt, x, y); - t.pop(); -} - -t.draw(() => { - t.background(10, 15, 20); - - const activeList = t.pressedKeys || []; - const count = activeList.length; - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - for (let y = -hh + 2; y <= hh - 2; y += 3) { - for (let x = -hw + 2; x <= hw - 2; x += 3) { - const isCross = (x + y) % 6 === 0; - t.push(); - t.translate(x, y); - t.charColor(22, 45, 35); - t.char(isCross ? '+' : '-'); - t.point(); - t.pop(); - } - } - - const numNodes = 12; - const ringRad = 12; - const activeNodes = new Set(); - - for (let i = 0; i < count; i++) { - const key = activeList[i]; - const code = typeof key === 'string' && key.length > 0 ? key.charCodeAt(0) : i; - activeNodes.add(code % numNodes); - } - - for (let i = 0; i < numNodes; i++) { - const ang = (i / numNodes) * Math.PI * 2 + tm; - const nx = Math.round(Math.cos(ang) * ringRad); - const ny = Math.round(Math.sin(ang) * (ringRad * 0.6)); - const isActive = activeNodes.has(i); - - t.push(); - t.translate(nx, ny); - if (isActive) { - t.charColor(255, 42, 95); - t.cellColor(90, 0, 30); - t.char('#'); - } else { - t.charColor(40, 90, 60); - t.char('.'); - } - t.point(); - t.pop(); - } - - if (count > 0) { - t.push(); - t.printAlign('center', 'middle'); - t.charColor(255, 238, 0); - t.print('CHORD: ' + activeList.slice(0, 5).join(' + ').toUpperCase(), 0, 0); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const activeList = t.pressedKeys || []; - - drawText('TEXTMODIFIER.PRESSEDKEYS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MULTI-KEY CHORD POLYPHONY', x, y++, 100, 220, 255); - drawText('Array lists all currently held keys.', x, y++, 140, 160, 190); - drawText('Hold multiple keys to form chords.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('HELD KEY COUNT: ' + activeList.length, x, y++, 140, 255, 180); - drawText('HELD KEYS: ' + activeList.slice(0, 4).join(', '), x, y++, 180, 200, 220); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/touches.md b/api/textmode.js/classes/Textmodifier/properties/touches.md index ecb39548..9d76be67 100644 --- a/api/textmode.js/classes/Textmodifier/properties/touches.md +++ b/api/textmode.js/classes/Textmodifier/properties/touches.md @@ -25,61 +25,5 @@ available. Use this inside a draw loop to react to active multi-touch scenarios. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let points = []; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - points = Array.from(t.touches); - if (points.length === 0 && t.mouseIsPressed) points = [t.mouse]; - for (let i = 0; i < points.length; i++) { - const p = points[i]; - t.push(); - t.translate(p.x, p.y); - t.char(String(i)); - t.charColor(255, 210, 120); - t.point(); - t.pop(); - if (i > 0) { - t.charColor(80, 120, 180); - t.line(points[i - 1].x, points[i - 1].y, p.x, p.y); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TOUCHES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACTIVE TOUCH LIST', x, y++, 100, 220, 255); - drawText('Shows live touch points.', x, y++, 140, 160, 190); - drawText('Mouse drag acts as fallback.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TOUCHES: ${points.length}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md index c8bf3975..517c07b3 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md @@ -22,81 +22,5 @@ Current browser window height in pixels. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let winH = 0; -let fill = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(7, 9, 19); - winH = t.windowHeight; - const halfRows = Math.floor(t.grid.rows / 2); - const top = -halfRows + 4; - const bottom = halfRows - 4; - const height = Math.max(6, bottom - top + 1); - const center = (top + bottom) / 2; - fill = t.constrain(Math.round(t.map(winH, 240, Math.max(241, t.displayHeight), 4, height)), 4, height); - - drawBand(-10, center, 1, height, 60, 120, 170); - drawBand(10, center, 1, height, 60, 120, 170); - drawBand(0, top, 21, 1, 42, 58, 92); - drawBand(0, bottom, 21, 1, 42, 58, 92); - drawBand(0, bottom - fill / 2 + 0.5, 1, fill, 125, 245, 185); - - for (let i = 0; i < height; i += 2) { - const y = bottom - i; - const width = Math.round(t.map(Math.cos(i * 0.55 + t.frameCount * 0.05), -1, 1, 3, 14)); - const active = i <= fill; - t.push(); - t.translate(0, y); - t.char(active ? '=' : '-'); - t.charColor(active ? 255 : 60, active ? 175 : 85, active ? 105 : 120); - t.rect(width, 1); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.WINDOWHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VIEWPORT HEIGHT', x, y++, 100, 220, 255); - drawText('windowHeight reads innerHeight live.', x, y++, 140, 160, 190); - drawText('Resize browser to lift the meter.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`HEIGHT: ${winH} PX`, x, y++, 140, 255, 180); - drawText(`CELLS: ${fill}`, x, y++, 255, 210, 120); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md index 6fef24f3..104a0e21 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md @@ -22,81 +22,5 @@ Current browser window width in pixels. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let winW = 0; -let fill = 0; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -function drawBand(x, y, width, height, r, g, b) { - t.push(); - t.translate(x, y); - t.char('█'); - t.charColor(r, g, b); - t.rect(width, height); - t.pop(); -} - -t.draw(() => { - t.background(5, 10, 18); - winW = t.windowWidth; - const halfCols = Math.floor(t.grid.cols / 2); - const left = -halfCols + 4; - const right = halfCols - 4; - const width = Math.max(6, right - left + 1); - const center = (left + right) / 2; - fill = t.constrain(Math.round(t.map(winW, 320, Math.max(321, t.displayWidth), 4, width)), 4, width); - - drawBand(center, -7, width, 1, 40, 55, 85); - drawBand(center, 7, width, 1, 40, 55, 85); - drawBand(left, 0, 1, 15, 75, 145, 190); - drawBand(right, 0, 1, 15, 75, 145, 190); - drawBand(left + fill / 2 - 0.5, 0, fill, 1, 120, 245, 190); - - for (let i = 0; i < width; i += 2) { - const x = left + i; - const height = Math.round(t.map(Math.sin(i * 0.4 + t.frameCount * 0.04), -1, 1, 2, 10)); - const active = i <= fill; - t.push(); - t.translate(x, 0); - t.char(active ? '#' : ':'); - t.charColor(active ? 120 : 45, active ? 220 : 70, active ? 255 : 110); - t.rect(1, height); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.WINDOWWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VIEWPORT WIDTH', x, y++, 100, 220, 255); - drawText('windowWidth reads innerWidth live.', x, y++, 140, 160, 190); - drawText('Resize browser to move the meter.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`WIDTH: ${winW} PX`, x, y++, 140, 255, 180); - drawText(`CELLS: ${fill}`, x, y++, 255, 210, 120); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/textmode.md b/api/textmode.js/classes/textmode.md index 76b51216..c5ee05f0 100644 --- a/api/textmode.js/classes/textmode.md +++ b/api/textmode.js/classes/textmode.md @@ -20,79 +20,7 @@ Use it to create [Textmodifier](Textmodifier.md) instances and configure global ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:+*#@'; - -t.draw(() => { - t.background(14, 6, 26); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.02; - - const n = 3 + Math.sin(tm * 0.5) * 1.5; - const m = 2 + Math.cos(tm * 0.7) * 1.5; - - for (let y = -hh; y <= hh; y++) { - const ny = (y / hh) * Math.PI; - for (let x = -hw; x <= hw; x++) { - const nx = (x / hw) * Math.PI; - - const chladni = Math.sin(n * nx) * Math.cos(m * ny) - Math.cos(m * nx) * Math.sin(n * ny); - const absVal = Math.abs(chladni); - - if (absVal < 0.6) { - const norm = 1 - absVal / 0.6; - const idx = Math.floor(norm * (RAMP.length - 1)); - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(180 + norm * 75), Math.floor(140 + norm * 70), Math.floor(40 + norm * 50)); - t.cellColor(Math.floor(25 + norm * 20), 8, Math.floor(40 + norm * 20)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODE.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CHLADNI NODAL RESONANCE', x, y++); - t.charColor(140, 160, 190); - t.print('Factory initialization setup.', x, y++); - t.print('Configures canvas & grid context.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 210, 90); - t.print('RESONANCE: ACTIVE', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Accessors diff --git a/api/textmode.js/classes/textmode/accessors/version.md b/api/textmode.js/classes/textmode/accessors/version.md index 07e202b4..9e610741 100644 --- a/api/textmode.js/classes/textmode/accessors/version.md +++ b/api/textmode.js/classes/textmode/accessors/version.md @@ -30,99 +30,5 @@ The package version string. ### Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); - -const v = textmode.version; -const label = t.layers.add(); -const len = v.length; -const PALETTE = [ - [255, 90, 90], - [90, 255, 130], - [90, 180, 255], - [255, 210, 60], - [210, 90, 255], - [60, 240, 220], -]; - -let px = 3; -let py = 2; -let dx = 0.32; -let dy = 0.22; -let ci = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 26); - const C = Math.floor(t.grid.cols / 2); - const R = Math.floor(t.grid.rows / 2); - - for (let x = -C; x <= C; x += 4) - for (let y = -R; y <= R; y += 3) - if ((x * 7 + y * 13) % 19 === 0) { - t.push(); - t.translate(x, y); - t.charColor(18, 26, 52); - t.char('.'); - t.point(); - t.pop(); - } - - px += dx; - py += dy; - - const left = -C; - const top = -R; - let bounced = false; - - if (px < left + 1) { - px = left + 1; - dx = Math.abs(dx); - bounced = true; - } - if (px + len > C - 1) { - px = C - len - 1; - dx = -Math.abs(dx); - bounced = true; - } - if (py < top + 1) { - py = top + 1; - dy = Math.abs(dy); - bounced = true; - } - if (py > R - 2) { - py = R - 2; - dy = -Math.abs(dy); - bounced = true; - } - - if (bounced) ci = (ci + 1) % PALETTE.length; - - t.printAlign('left', 'top'); - t.charColor(PALETTE[ci][0], PALETTE[ci][1], PALETTE[ci][2]); - t.print(v, Math.round(px), Math.round(py)); -}); - -label.draw(() => { - t.clear(); - const L = -Math.floor(t.grid.cols / 2), - T = -Math.floor(t.grid.rows / 2); - let y = T + 3; - drawText('TEXTMODE.VERSION', L + 3, y++, [100, 255, 140]); - drawText('------------------------------------', L + 3, y++, [80, 100, 150]); - drawText('CONCEPT: BOUNCING VERSION', L + 3, y++, [100, 220, 255]); - drawText(`Bounces: ${ci}`, L + 3, y++, [140, 160, 190]); - drawText('------------------------------------', L + 3, y++, [80, 100, 150]); - drawText(`VERSION: ${v}`, L + 3, y++, [140, 255, 180]); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/classes/textmode/methods/create.md b/api/textmode.js/classes/textmode/methods/create.md index fdfe22eb..b8db4823 100644 --- a/api/textmode.js/classes/textmode/methods/create.md +++ b/api/textmode.js/classes/textmode/methods/create.md @@ -34,70 +34,5 @@ The created Textmodifier instance. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = '.+*#%@'; - -t.draw(() => { - t.background(6, 20, 14); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x * 0.8, y); - const ring = (Math.sin(dist * 0.4 - tm) + 1) * 0.5; - const hexPattern = Math.abs(Math.sin(x * 0.3) * Math.cos(y * 0.3)); - - const val = ring * 0.7 + hexPattern * 0.3; - if (val > 0.4) { - const idx = Math.floor(((val - 0.4) / 0.6) * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(Math.floor(40 + val * 180), Math.floor(180 + val * 75), Math.floor(120 + val * 100)); - t.cellColor(4, Math.floor(16 + val * 30), 10); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODE.CREATE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: GENESIS MATRIX WAVEFRONT', x, y++); - t.charColor(140, 160, 190); - t.print('Instantiates a Textmodifier instance.', x, y++); - t.print('Initializes grid resolution & context.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`GRID SIZE: ${t.grid.cols}x${t.grid.rows} CELLS`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/classes/textmode/methods/setErrorLevel.md b/api/textmode.js/classes/textmode/methods/setErrorLevel.md index b302addd..aaf24a3c 100644 --- a/api/textmode.js/classes/textmode/methods/setErrorLevel.md +++ b/api/textmode.js/classes/textmode/methods/setErrorLevel.md @@ -32,101 +32,5 @@ Set the global error handling level for all [Textmodifier](../../Textmodifier.md ## Example -```javascript -const levels = [ - { name: 'SILENT', value: TextmodeErrorLevel.SILENT, summary: 'no output' }, - { name: 'WARNING', value: TextmodeErrorLevel.WARNING, summary: 'console.warn()' }, - { name: 'ERROR', value: TextmodeErrorLevel.ERROR, summary: 'console.error()' }, - { name: 'THROW', value: TextmodeErrorLevel.THROW, summary: 'throws' }, -]; - -let activeIndex = 1; -textmode.setErrorLevel(levels[activeIndex].value); - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -const rhoPerLevel = [14, 28, 55, 115]; -let state = { x: 1, y: 1, z: 1 }; -const trail = []; - -t.draw(() => { - const cycle = 180; - const idx = Math.floor(t.frameCount / cycle) % levels.length; - - if (idx !== activeIndex) { - activeIndex = idx; - textmode.setErrorLevel(levels[activeIndex].value); - state = { x: 1, y: 1, z: 1 }; - trail.length = 0; - } - - t.background(18, 20, 28); - - const rho = rhoPerLevel[activeIndex]; - const dt = 0.005; - const level = activeIndex / (levels.length - 1); - - for (let s = 0; s < 3; s++) { - state.x += 10 * (state.y - state.x) * dt; - state.y += (state.x * (rho - state.z) - state.y) * dt; - state.z += (state.x * state.y - (state.z * 8) / 3) * dt; - trail.push({ - x: Math.round(state.x * 0.55), - y: Math.round((state.z - rho * 0.6) * 0.55), - }); - } - - if (trail.length > 130) trail.splice(0, trail.length - 130); - - for (let i = 0; i < trail.length; i++) { - const p = trail[i]; - const q = i / trail.length; - - t.push(); - t.translate(p.x, p.y); - t.charColor(60 + level * 195, 180 - level * 140, 80 + level * 175); - t.char(q > 0.7 ? '@' : q > 0.4 ? '+' : '.'); - t.point(); - t.pop(); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const level = levels[activeIndex]; - const meter = levels.map((_, i) => (i <= activeIndex ? '|' : '.')).join(''); - - drawText('TEXTMODE.SETERRORLEVEL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLOBAL ERROR HANDLING', x, y++, 100, 220, 255); - drawText('Sets library diagnostic severity.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ACTIVE LEVEL: ${level.name}`, x, y++, 255, 210, 90); - drawText(`LEVEL METER : ${meter}`, x, y++, 255, 210, 90); - drawText(`BEHAVIOR : ${level.summary}`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/enumerations/ShapeAssemblyMode.md b/api/textmode.js/enumerations/ShapeAssemblyMode.md index 4c9c050c..97b105b9 100644 --- a/api/textmode.js/enumerations/ShapeAssemblyMode.md +++ b/api/textmode.js/enumerations/ShapeAssemblyMode.md @@ -31,60 +31,7 @@ the last vertex should connect back to the first. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINE_LOOP; -const modeName = 'LINE_LOOP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(7, 10, 24); - t.lineWeight(0.7); - t.beginShape(mode); - for (let i = 0; i < 64; i++) { - const p = i / 64; - const a = p * Math.PI * 2; - const r = 10 + Math.sin(a * 5 + time * 2) * 2 + Math.cos(a * 3 - time) * 1.5; - t.char(i % 5 === 0 ? '#' : '+'); - t.charColor(120 + Math.sin(a) * 80, 210, 180 + Math.cos(a) * 60); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINE_LOOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLOSED OUTLINE', x, y++, 100, 220, 255); - drawText('Last vertex returns to first.', x, y++, 140, 160, 190); - drawText('Good for orbiting contours.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -101,60 +48,7 @@ paths that should not automatically close. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINE_STRIP; -const modeName = 'LINE_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(5, 12, 25); - t.lineWeight(0.8); - t.beginShape(mode); - for (let i = 0; i < 70; i++) { - const p = i / 69; - const x = -22 + p * 44; - const y = Math.sin(p * Math.PI * 6 + time * 2) * 5 + Math.sin(p * 19 - time) * 2; - t.char(i % 4 === 0 ? '@' : '~'); - t.charColor(80 + p * 160, 170 + Math.sin(p * 7) * 70, 255); - t.vertex(x, y); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINE_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: OPEN CONTINUOUS PATH', x, y++, 100, 220, 255); - drawText('Consecutive vertices connect.', x, y++, 140, 160, 190); - drawText('The ends remain open.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -171,61 +65,7 @@ geometry where every two vertices form a separate edge. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.LINES; -const modeName = 'LINES'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 8, 22); - t.lineWeight(0.7); - t.beginShape(mode); - for (let i = 0; i < 30; i++) { - const a = i * 12 + t.frameCount * 0.9; - const r1 = 4 + Math.sin(time + i) * 2; - const r2 = 13 + Math.cos(time * 1.7 + i) * 3; - t.char(i % 2 ? '/' : '\\'); - t.charColor(120 + i * 4, 240 - i * 3, 210); - t.vertex(Math.cos(a) * r1, Math.sin(a) * r1); - t.vertex(Math.cos(a + 30) * r2, Math.sin(a + 30) * r2); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.LINES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PAIRED SEGMENTS', x, y++, 100, 220, 255); - drawText('Every two vertices connect.', x, y++, 140, 160, 190); - drawText('Each pair stays separate.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -242,59 +82,7 @@ where every vertex is an independent mark. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.POINTS; -const modeName = 'POINTS'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(6, 10, 24); - t.beginShape(mode); - for (let i = 0; i < 96; i++) { - const a = i * 13.7 + t.frameCount * 1.4; - const r = 2 + i * 0.12 + Math.sin(time * 2 + i) * 1.2; - t.char(i % 3 === 0 ? '*' : '.'); - t.charColor(90 + i, 180 + Math.sin(i) * 50, 255); - t.cellColor(4, 12 + (i % 6) * 5, 30); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.POINTS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VERTEX PARTICLES', x, y++, 100, 220, 255); - drawText('Each vertex becomes a point.', x, y++, 140, 160, 190); - drawText('No edges connect the marks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -311,62 +99,7 @@ pair of vertices extends the next four-sided segment. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.QUAD_STRIP; -const modeName = 'QUAD_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(8, 8, 24); - t.beginShape(mode); - for (let i = 0; i < 28; i++) { - const p = i / 27; - const x = -20 + p * 40; - const y = Math.sin(p * Math.PI * 4 + time * 2) * 5; - const width = 2 + Math.cos(time + i) * 0.8; - t.char(i % 2 ? '=' : '#'); - t.charColor(255 - p * 80, 140 + p * 90, 210); - t.cellColor(40 + p * 30, 16, 45 + p * 40); - t.vertex(x, y - width); - t.vertex(x, y + width); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.QUAD_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONNECTED QUAD BAND', x, y++, 100, 220, 255); - drawText('Each pair extends the strip.', x, y++, 140, 160, 190); - drawText('Good for thick flowing paths.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -383,65 +116,7 @@ every four vertices define a separate four-sided patch. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.QUADS; -const modeName = 'QUADS'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(6, 10, 20); - t.beginShape(mode); - for (let gy = -2; gy <= 2; gy++) { - for (let gx = -4; gx <= 4; gx++) { - const cx = gx * 4 + Math.sin(time + gy) * 1.5; - const cy = gy * 4 + Math.cos(time + gx) * 1.5; - const s = 1.4 + Math.sin(time * 2 + gx + gy) * 0.5; - t.char((gx + gy) % 2 ? '#' : '+'); - t.charColor(120 + gx * 14, 190 + gy * 12, 250); - t.cellColor(12 + gx * 3, 22 + gy * 6, 45); - t.vertex(cx - s, cy - s); - t.vertex(cx + s, cy - s); - t.vertex(cx + s, cy + s); - t.vertex(cx - s, cy + s); - } - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.QUADS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FOUR VERTEX PATCHES', x, y++, 100, 220, 255); - drawText('Every four vertices fill.', x, y++, 140, 160, 190); - drawText('Each cell is independent.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -458,64 +133,7 @@ expanding from a shared center. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLE_FAN; -const modeName = 'TRIANGLE_FAN'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(10, 8, 24); - t.beginShape(mode); - t.char('@'); - t.charColor(255, 245, 180); - t.cellColor(65, 40, 20); - t.vertex(0, 0); - for (let i = 0; i <= 48; i++) { - const p = i / 48; - const a = p * Math.PI * 2 + time; - const r = 12 + Math.sin(a * 6 - time * 3) * 2; - t.char(i % 3 ? '*' : '#'); - t.charColor(255, 130 + Math.sin(a) * 70, 90 + Math.cos(a) * 60); - t.cellColor(55 + Math.sin(a) * 20, 18, 12); - t.vertex(Math.cos(a) * r, Math.sin(a) * r); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLE_FAN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SHARED CENTER', x, y++, 100, 220, 255); - drawText('Every triangle uses vertex 1.', x, y++, 140, 160, 190); - drawText('Great for radial bursts.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -532,61 +150,7 @@ built from a single alternating vertex sequence. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLE_STRIP; -const modeName = 'TRIANGLE_STRIP'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(5, 12, 26); - t.beginShape(mode); - for (let i = 0; i < 42; i++) { - const p = i / 41; - const x = -20 + p * 40; - const wave = Math.sin(p * Math.PI * 5 + time * 2) * 4; - const side = i % 2 === 0 ? -2.5 : 2.5; - t.char(i % 2 === 0 ? '/' : '\\'); - t.charColor(100 + p * 120, 240 - p * 70, 255); - t.cellColor(8, 28 + p * 40, 45 + p * 70); - t.vertex(x, wave + side); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLE_STRIP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONNECTED RIBBON', x, y++, 100, 220, 255); - drawText('Each new vertex adds a face.', x, y++, 140, 160, 190); - drawText('Alternating sides make width.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -603,60 +167,4 @@ each triangle controls its own three corners. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.TRIANGLES; -const modeName = 'TRIANGLES'; -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 8, 20); - t.beginShape(mode); - for (let i = 0; i < 18; i++) { - const a = i * 20 + t.frameCount; - const cx = Math.cos(a) * (5 + (i % 3) * 4); - const cy = Math.sin(a) * (5 + (i % 4) * 2); - const size = 2 + Math.sin(time + i) * 0.8; - t.char(i % 2 ? '^' : '#'); - t.charColor(250, 110 + i * 6, 150 + i * 3); - t.cellColor(40 + i * 4, 10, 25); - t.vertex(cx + Math.cos(a) * size, cy + Math.sin(a) * size); - t.vertex(cx + Math.cos(a + 120) * size, cy + Math.sin(a + 120) * size); - t.vertex(cx + Math.cos(a + 240) * size, cy + Math.sin(a + 240) * size); - } - t.endShape(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.TRIANGLES', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INDEPENDENT FACETS', x, y++, 100, 220, 255); - drawText('Every three vertices fill.', x, y++, 140, 160, 190); - drawText('Each triangle stands alone.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor.md b/api/textmode.js/namespaces/color/classes/TextmodeColor.md index 16a009ee..62fd21b7 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor.md @@ -24,92 +24,7 @@ Use [Textmodifier.color](../../../classes/Textmodifier/methods/color.md) to crea ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 6, 14); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - - const cRgb = t.color(240, 80, 50); - const cHex = t.color('#30E0A0'); - const cGray = t.color(180); - const cRgba = t.color(90, 140, 255, 200); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const manhattan = Math.abs(x) + Math.abs(y); - const chebyshev = Math.max(Math.abs(x), Math.abs(y)); - const ring = Math.floor(manhattan * 0.4 + chebyshev * 0.3 - tm) % 4; - - let col; - if (ring === 0) col = cRgb; - else if (ring === 1) col = cHex; - else if (ring === 2) col = cGray; - else col = cRgba; - - const val = (Math.sin(manhattan * 0.3 - tm) + 1) * 0.5; - if (val > 0.15) { - const idx = Math.min(RAMP.length - 1, Math.floor(val * RAMP.length)); - t.push(); - t.translate(x, y); - t.charColor(col.r, col.g, col.b); - t.cellColor(Math.floor(col.r * 0.12), Math.floor(col.g * 0.12), Math.floor(col.b * 0.12)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const cRgb = t.color(240, 80, 50); - const cHex = t.color('#30E0A0'); - const cGray = t.color(180); - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: COLOR CONSTRUCTOR FORMATS', x, y++); - t.charColor(140, 160, 190); - t.print('Creates instances from RGB, Hex,', x, y++); - t.print('grayscale, and RGBA arguments.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(cRgb.r, cRgb.g, cRgb.b); - t.print(`RGB : t.color(${cRgb.r}, ${cRgb.g}, ${cRgb.b})`, x, y++); - t.charColor(cHex.r, cHex.g, cHex.b); - t.print("HEX : t.color('#30E0A0')", x, y++); - t.charColor(cGray.r, cGray.g, cGray.b); - t.print(`GRAY: t.color(${cGray.r})`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Properties diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md index 2cf20bd2..3c2d905f 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md @@ -33,78 +33,5 @@ A [r, g, b, a] tuple where each component is between 0.0 and 1.0. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const time = t.frameCount * 0.025; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const r = Math.floor((Math.sin(x * 0.12 + time) * 0.5 + 0.5) * 255); - const g = Math.floor((Math.cos(y * 0.14 - time * 0.8) * 0.5 + 0.5) * 255); - const b = Math.floor((Math.sin(x * 0.08 + y * 0.08 + time * 1.4) * 0.5 + 0.5) * 255); - - const col = t.color(r, g, b); - const [nr, ng, nb] = col.normalized; - - const lum = nr * 0.3 + ng * 0.59 + nb * 0.11; - if (lum > 0.25) { - const normLum = (lum - 0.25) / 0.75; - const idx = Math.min(RAMP.length - 1, Math.floor(normLum * RAMP.length)); - - t.push(); - t.translate(x, y); - t.charColor(nr * 255, ng * 255, nb * 255); - t.cellColor(nr * 35, ng * 35, nb * 35); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(255, 128, 64); - const [nr, ng, nb] = sampleCol.normalized; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.NORMALIZED', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: NORMALIZED RGBA CHANNELS', x, y++); - t.charColor(140, 160, 190); - t.print('Returns [0..1] float array for RGBA.', x, y++); - t.print('Drives luminance & cell tinting.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE NORM: [${nr.toFixed(2)}, ${ng.toFixed(2)}, ${nb.toFixed(2)}]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md index 4e0e92e0..18f1e940 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md @@ -31,89 +31,5 @@ A [r, g, b] tuple with values between 0 and 255. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 6, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - - const rx = Math.sin(tm * 1.2) * (hw * 0.6); - const ry = Math.cos(tm * 0.8) * (hh * 0.6); - - const gx = Math.cos(tm * 0.9 + 1.5) * (hw * 0.6); - const gy = Math.sin(tm * 1.3 + 1.5) * (hh * 0.6); - - const bx = Math.sin(tm * 0.7 + 3.0) * (hw * 0.6); - const by = Math.cos(tm * 1.1 + 3.0) * (hh * 0.6); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dr = Math.hypot(x - rx, y - ry); - const dg = Math.hypot(x - gx, y - gy); - const db = Math.hypot(x - bx, y - by); - - const rVal = Math.floor(Math.max(0, 255 - dr * 14)); - const gVal = Math.floor(Math.max(0, 255 - dg * 14)); - const bVal = Math.floor(Math.max(0, 255 - db * 14)); - - const col = t.color(rVal, gVal, bVal); - const [r, g, b] = col.rgb; - - const maxVal = Math.max(r, g, b); - if (maxVal > 30) { - const idx = Math.min(RAMP.length - 1, Math.floor((maxVal / 255) * RAMP.length)); - t.push(); - t.translate(x, y); - t.charColor(r, g, b); - t.cellColor(Math.floor(r * 0.18), Math.floor(g * 0.18), Math.floor(b * 0.18)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(240, 120, 60); - const [r, g, b] = sampleCol.rgb; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.RGB', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: KINETIC RGB LASER WEAVER', x, y++); - t.charColor(140, 160, 190); - t.print('Extracts [r, g, b] tuple array.', x, y++); - t.print('Weaves Lissajous light nodes.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE RGB: [${r}, ${g}, ${b}]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md index 9ab11438..25f34379 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md @@ -31,101 +31,5 @@ A [r, g, b, a] tuple with values between 0 and 255. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const topLayer = t.layers.add({ blendMode: 'normal' }); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(10, 10, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - if ((x + y) % 3 === 0) { - t.push(); - t.translate(x, y); - t.charColor(50, 60, 80); - t.char('.'); - t.point(); - t.pop(); - } - } - } -}); - -topLayer.draw(() => { - t.clear(); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - const d1x = Math.cos(tm) * (hw * 0.3); - const d1y = Math.sin(tm) * (hh * 0.3); - const d2x = Math.cos(tm + 2.1) * (hw * 0.3); - const d2y = Math.sin(tm + 2.1) * (hh * 0.3); - const rad = Math.min(hw, hh) * 0.45; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const in1 = Math.hypot(x - d1x, y - d1y) < rad; - const in2 = Math.hypot(x - d2x, y - d2y) < rad; - if (in1 || in2) { - const col = t.color( - in2 ? 240 : 40, - in1 && in2 ? 220 : in1 ? 200 : 180, - in1 ? 240 : 40, - in1 && in2 ? 220 : 140 - ); - const [cr, cg, cb, ca] = col.rgba; - const idx = Math.min(RAMP.length - 1, Math.floor((ca / 255) * RAMP.length)); - t.push(); - t.translate(x, y); - t.charColor(cr, cg, cb, ca); - t.cellColor(Math.floor(cr * 0.2), Math.floor(cg * 0.2), Math.floor(cb * 0.2), ca); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(40, 200, 240, 140); - const [r, g, b, a] = sampleCol.rgba; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.RGBA', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: OVERLAPPING RGBA DISKS', x, y++); - t.charColor(140, 160, 190); - t.print('Unpacks [r, g, b, a] tuple array.', x, y++); - t.print('Composites translucent orbital lenses.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE RGBA: [${r}, ${g}, ${b}, ${a}]`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md index 27cdfb8c..31be15c5 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md @@ -38,58 +38,5 @@ A new TextmodeColor instance with the updated alpha. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const layers = Array.from({ length: 5 }, () => t.layers.add()); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(0); -}); - -layers.forEach((layer, i) => { - layer.draw(() => { - t.clear(); - - const base = t.color(50, 150, 255); - const opacity = 100 + i * 30; - - t.push(); - t.translate((i - 2) * 5, Math.sin(t.frameCount * 0.05 + i) * 5); - t.charColor(base.withAlpha(opacity)); - t.cellColor(0, 0, 0, 0); - t.char(String.fromCharCode(65 + i)); - t.rect(12, 12); - t.pop(); - }); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODECOLOR.WITHALPHA', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLONE COLOR WITH NEW ALPHA', x, y++, 100, 220, 255); - drawText('Returns copy with adjusted opacity.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Rendering layers A-E with alpha.', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md index 20209b72..c9bff067 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md @@ -23,97 +23,5 @@ Alpha component (0-255). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const fogLayer = t.layers.add({ blendMode: 'normal' }); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(14, 14, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const gridPattern = Math.abs(x % 4 === 0 || y % 4 === 0 ? 1 : 0); - if (gridPattern) { - t.push(); - t.translate(x, y); - t.charColor(240, 80, 40); - t.cellColor(40, 16, 10); - t.char('+'); - t.point(); - t.pop(); - } - } - } -}); - -fogLayer.draw(() => { - t.clear(); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(x * 0.15 + tm) * Math.cos(y * 0.15 - tm * 0.8); - const alphaVal = Math.floor(Math.max(0, Math.min(255, (wave + 1) * 0.5 * 255))); - - const col = t.color(60, 200, 230, alphaVal); - const a = col.a; - - if (a > 30) { - const idx = Math.floor((a / 255) * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(col.r, col.g, col.b, a); - t.cellColor(10, 40, 50, a); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(60, 200, 230, 180); - const a = sampleCol.a; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.A', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: DISSOLVE FOG MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('Top layer col.a modulates opacity.', x, y++); - t.print('Reveals crimson geometric backdrop.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE ALPHA: ${a} / 255`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md index a58f5022..1a47b901 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md @@ -23,78 +23,5 @@ Blue component (0-255). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 22); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const d1 = Math.hypot(x - Math.cos(tm) * 8, y - Math.sin(tm) * 6); - const d2 = Math.hypot(x + Math.sin(tm * 0.7) * 8, y + Math.cos(tm * 0.7) * 6); - const wave = (Math.sin(d1 * 0.3 - tm * 1.5) + Math.cos(d2 * 0.3 - tm * 1.2)) * 0.5; - const blueVal = Math.floor(Math.max(0, Math.min(255, (wave * 0.5 + 0.5) * 220 + 35))); - - const col = t.color(15, Math.floor(blueVal * 0.5), blueVal); - const blue = col.b; - - if (blue > 45) { - const norm = (blue - 45) / 210; - const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); - - t.push(); - t.translate(x, y); - t.charColor(col.r, col.g, blue); - t.cellColor(4, 12, Math.floor(blue * 0.25)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(15, 120, 240); - const blue = sampleCol.b; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.B', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: READ BLUE COLOR CHANNEL', x, y++); - t.charColor(140, 160, 190); - t.print('Reads 8-bit blue property (0-255).', x, y++); - t.print('Drives oceanic caustic ripples.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE BLUE: ${blue} / 255`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md index 50142ed6..4b22bebc 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md @@ -23,76 +23,5 @@ Green component (0-255). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 14, 12); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.025; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const lattice = Math.sin((x + y) * 0.2 + tm) * Math.cos((x - y) * 0.2 - tm * 0.7); - const greenVal = Math.floor(Math.max(0, Math.min(255, (lattice * 0.5 + 0.5) * 220 + 35))); - - const col = t.color(20, greenVal, Math.floor(greenVal * 0.35)); - const green = col.g; - - if (green > 50) { - const norm = (green - 50) / 205; - const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); - - t.push(); - t.translate(x, y); - t.charColor(col.r, green, col.b); - t.cellColor(4, Math.floor(green * 0.24), 8); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(20, 220, 80); - const green = sampleCol.g; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.G', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: READ GREEN COLOR CHANNEL', x, y++); - t.charColor(140, 160, 190); - t.print('Reads 8-bit green property (0-255).', x, y++); - t.print('Drives bioluminescent grid density.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE GREEN: ${green} / 255`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md index 45ef4b6f..accb3b1f 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md @@ -23,81 +23,5 @@ Red component (0-255). ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(8, 6, 12); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - const fx = Math.cos(tm * 0.8) * (hw * 0.35); - const fy = Math.sin(tm * 0.6) * (hh * 0.35); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const d = Math.hypot(x - fx, y - fy); - const angle = Math.atan2(y - fy, x - fx); - const wave = Math.sin(d * 0.35 - angle * 2 - tm * 2); - const redVal = Math.floor(Math.max(0, Math.min(255, (wave * 0.5 + 0.5) * 230 + 25))); - - const col = t.color(redVal, Math.floor(redVal * 0.25), 30); - const red = col.r; - - if (red > 45) { - const norm = (red - 45) / 210; - const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); - - t.push(); - t.translate(x, y); - t.charColor(red, col.g, col.b); - t.cellColor(Math.floor(red * 0.22), 6, 10); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sampleCol = t.color(240, 60, 30); - const red = sampleCol.r; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODECOLOR.R', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: READ RED COLOR CHANNEL', x, y++); - t.charColor(140, 160, 190); - t.print('Reads 8-bit red property (0-255).', x, y++); - t.print('Drives stellar flare density.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`SAMPLE RED: ${red} / 255`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md index 4a9688e9..c408ad66 100644 --- a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md +++ b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md @@ -58,99 +58,7 @@ true if the strategy exists #### Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let hasCustom = false; -let pulseShader = null; - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_uv; - out vec2 v_uv; - void main() { - gl_Position = a_position; - v_uv = a_uv; - } - `; - - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_image; - layout(location = 0) out vec4 o_character; - layout(location = 1) out vec4 o_primaryColor; - layout(location = 2) out vec4 o_secondaryColor; - void main() { - vec4 col = texture(u_image, v_uv); - o_character = vec4(col.r, 0.0, 0.0, 0.0); - o_primaryColor = vec4(col.rgb, 1.0); - o_secondaryColor = vec4(0.0, 0.0, 0.0, 1.0); - } - `; - - pulseShader = await t.createShader(vert, frag); -}); - -t.draw(() => { - t.background(6, 8, 20); - hasCustom = t.conversions.has('custom-mode'); -}); - -t.mouseClicked(() => { - if (hasCustom) { - t.conversions.unregister('custom-mode'); - } else { - t.conversions.register({ - id: 'custom-mode', - createShader: () => pulseShader, - createUniforms: (ctx) => ({ u_image: ctx.source.texture }), - }); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const isDefault = t.conversions.has('brightness'); - - drawText('CONVERSION.HAS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CHECK REGISTERED STRATEGY', x, y++, 100, 220, 255); - drawText('Performs a key lookup in conversions.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`has('brightness') : ${isDefault}`, x, y++, 180, 255, 180); - drawText( - `has('custom-mode'): ${hasCustom}`, - x, - y++, - hasCustom ? 180 : 255, - hasCustom ? 255 : 120, - hasCustom ? 180 : 120 - ); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(hasCustom ? 'Click to unregister.' : 'Click to register custom-mode.', x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + *** @@ -207,82 +115,5 @@ true if the strategy was unregistered, false if it wasn't found #### Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let img = null; -let registered = false; -let customShader = null; - -t.setup(async () => { - const vert = `#version 300 es\nin vec4 a_position; in vec2 a_uv; out vec2 v_uv; void main() { gl_Position = a_position; v_uv = a_uv; }`; - const frag = `#version 300 es\nprecision highp float; in vec2 v_uv; uniform sampler2D u_image; layout(location = 0) out vec4 o_character; layout(location = 1) out vec4 o_primaryColor; layout(location = 2) out vec4 o_secondaryColor; void main() { vec4 col = texture(u_image, v_uv); float greenLuma = col.g; o_character = vec4(greenLuma * 0.8, 0.0, 0.0, 0.0); o_primaryColor = vec4(0.1, 0.9, 0.3, 1.0); o_secondaryColor = vec4(0.01, 0.05, 0.02, 1.0); }`; - - customShader = await t.createShader(vert, frag); - - t.conversions.register({ - id: 'green-custom', - createShader: () => customShader, - createUniforms: (ctx) => ({ u_image: ctx.source.texture }), - }); - - img = await t.loadImage(IMAGE_URL); - img.characters(' .:-=+*#%@'); - img.conversionMode('green-custom'); - registered = true; -}); - -t.draw(() => { - t.background(6, 8, 20); - if (img) { - t.image(img, t.grid.cols - 8, t.grid.rows - 10); - } -}); - -t.mouseClicked(() => { - if (!registered || !img) return; - img.conversionMode('brightness'); - t.conversions.unregister('green-custom'); - registered = false; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const mode = registered ? 'green-custom' : 'brightness'; - - drawText('CONVERSION.UNREGISTER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISPOSE CONVERSION STRATEGY', x, y++, 100, 220, 255); - drawText('Removes registered custom logic.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`ACTIVE MODE: ${mode}`, x, y++, 140, 190, 255); - drawText( - registered ? 'Click to unregister green-custom.' : 'Strategy unregistered successfully.', - x, - y++, - 180, - 255, - 180 - ); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md index 21391fd9..5c1c09ae 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md @@ -50,93 +50,5 @@ brightness range, and character palette texture for the active pass. #### Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let img = null; -let animatedShader = null; - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_uv; - out vec2 v_uv; - void main() { - gl_Position = a_position; - v_uv = a_uv; - } - `; - - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_image; - uniform float u_time; - layout(location = 0) out vec4 o_character; - layout(location = 1) out vec4 o_primaryColor; - layout(location = 2) out vec4 o_secondaryColor; - void main() { - vec4 col = texture(u_image, v_uv); - float wave = 0.5 + 0.5 * sin(u_time + v_uv.x * 12.0); - float luma = dot(col.rgb, vec3(0.299, 0.587, 0.114)); - o_character = vec4(luma * wave * 0.95, 0.0, 0.0, 0.0); - o_primaryColor = vec4(col.r, col.g * wave, col.b * 1.5, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.06, 1.0); - } - `; - - animatedShader = await t.createShader(vert, frag); - - t.conversions.register({ - id: 'time-wave', - createShader: () => animatedShader, - createUniforms: (ctx) => ({ - ...ctx.createBaseUniforms(), - u_time: t.frameCount * 0.04, - }), - }); - - img = await t.loadImage(IMAGE_URL); - img.characters(' .:-=+*#%@'); - img.conversionMode('time-wave'); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (img) { - t.image(img, t.grid.cols - 8, t.grid.rows - 10); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const timeVal = t.frameCount * 0.04; - - drawText('CONVERSION.CREATEUNIFORMS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RENDERING UNIFORMS BINDING', x, y++, 100, 220, 255); - drawText('Binds time-based animation values.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TIME UNIFORM: ${timeVal.toFixed(2)}`, x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md index 556fbddc..87e4ef4b 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md @@ -59,88 +59,7 @@ The compiled GLShader instance. #### Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let img = null; -let blueShader = null; - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_uv; - out vec2 v_uv; - void main() { - gl_Position = a_position; - v_uv = a_uv; - } - `; - - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_image; - layout(location = 0) out vec4 o_character; - layout(location = 1) out vec4 o_primaryColor; - layout(location = 2) out vec4 o_secondaryColor; - void main() { - vec4 col = texture(u_image, v_uv); - float blueLuma = col.b; - o_character = vec4(blueLuma * 0.9, 0.0, 0.0, 0.0); - o_primaryColor = vec4(0.2, 0.6, 1.0, 1.0); - o_secondaryColor = vec4(0.01, 0.03, 0.08, 1.0); - } - `; - - blueShader = await t.createShader(vert, frag); - - t.conversions.register({ - id: 'blue-mrt', - createShader: () => blueShader, - createUniforms: (ctx) => ({ u_image: ctx.source.texture }), - }); - - img = await t.loadImage(IMAGE_URL); - img.characters(' .:-=+*#%@'); - img.conversionMode('blue-mrt'); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (img) { - t.image(img, t.grid.cols - 8, t.grid.rows - 10); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('CONVERSION.CREATESHADER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DYNAMIC SHADER REGISTER', x, y++, 100, 220, 255); - drawText('Outputs custom MRT locations for', x, y++, 140, 160, 190); - drawText('character, primary & secondary.', x, y++, 140, 160, 190); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + *** @@ -169,93 +88,5 @@ An object mapping uniform names to values. #### Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let img = null; -let animatedShader = null; - -t.setup(async () => { - const vert = `#version 300 es - in vec4 a_position; - in vec2 a_uv; - out vec2 v_uv; - void main() { - gl_Position = a_position; - v_uv = a_uv; - } - `; - - const frag = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_image; - uniform float u_time; - layout(location = 0) out vec4 o_character; - layout(location = 1) out vec4 o_primaryColor; - layout(location = 2) out vec4 o_secondaryColor; - void main() { - vec4 col = texture(u_image, v_uv); - float wave = 0.5 + 0.5 * sin(u_time + v_uv.x * 12.0); - float luma = dot(col.rgb, vec3(0.299, 0.587, 0.114)); - o_character = vec4(luma * wave * 0.95, 0.0, 0.0, 0.0); - o_primaryColor = vec4(col.r, col.g * wave, col.b * 1.5, 1.0); - o_secondaryColor = vec4(0.02, 0.03, 0.06, 1.0); - } - `; - - animatedShader = await t.createShader(vert, frag); - - t.conversions.register({ - id: 'time-wave', - createShader: () => animatedShader, - createUniforms: (ctx) => ({ - ...ctx.createBaseUniforms(), - u_time: t.frameCount * 0.04, - }), - }); - - img = await t.loadImage(IMAGE_URL); - img.characters(' .:-=+*#%@'); - img.conversionMode('time-wave'); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (img) { - t.image(img, t.grid.cols - 8, t.grid.rows - 10); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const timeVal = t.frameCount * 0.04; - - drawText('CONVERSION.CREATEUNIFORMS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: RENDERING UNIFORMS BINDING', x, y++, 100, 220, 255); - drawText('Binds time-based animation values.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`TIME UNIFORM: ${timeVal.toFixed(2)}`, x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md index 1e145306..f55d7a92 100644 --- a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md +++ b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md @@ -57,96 +57,7 @@ true if the filter exists #### Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let hasCustom = false; - -t.setup(async () => { - const fragment = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_src; - out vec4 outColor; - void main() { - outColor = texture(u_src, v_uv); - } - `; - - await t.filters.register('custom-noop', fragment, {}); -}); - -t.draw(() => { - t.background(6, 9, 20); - - hasCustom = t.filters.has('custom-noop'); - - t.push(); - t.char('#'); - t.rotateZ(t.frameCount * 1.5); - t.charColor(255, 220, 120); - t.rect(12, 12); - t.pop(); -}); - -t.mouseClicked(async () => { - if (hasCustom) { - t.filters.unregister('custom-noop'); - } else { - const fragment = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_src; - out vec4 outColor; - void main() { - outColor = texture(u_src, v_uv); - } - `; - await t.filters.register('custom-noop', fragment, {}); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const isInvert = t.filters.has('invert'); - - drawText('FILTERS.HAS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CHECK REGISTERED FILTER', x, y++, 100, 220, 255); - drawText('Performs lookup in filter registry.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`has('invert') : ${isInvert}`, x, y++, 180, 255, 180); - drawText( - `has('custom-noop'): ${hasCustom}`, - x, - y++, - hasCustom ? 180 : 255, - hasCustom ? 255 : 120, - hasCustom ? 180 : 120 - ); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(hasCustom ? 'Click to unregister.' : 'Click to register custom-noop.', x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + *** @@ -213,84 +124,5 @@ true if the filter was unregistered, false if it wasn't found #### Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight }); - -const labelLayer = t.layers.add(); -let filterActive = false; - -t.setup(async () => { - const fragment = `#version 300 es - precision highp float; - in vec2 v_uv; - uniform sampler2D u_src; - out vec4 outColor; - void main() { - vec4 col = texture(u_src, v_uv); - outColor = vec4(col.r * 0.1, col.g * 1.5, col.b * 0.2, col.a); - } - `; - - await t.filters.register('green-wash', fragment, {}); - filterActive = true; -}); - -t.draw(() => { - t.background(6, 9, 20); - - t.push(); - t.char('#'); - t.rotateZ(t.frameCount * 1.2); - t.charColor(255, 220, 120); - t.rect(14, 14); - t.pop(); - - if (filterActive && t.filters.has('green-wash')) { - t.filter('green-wash'); - } -}); - -t.mouseClicked(() => { - if (!filterActive) return; - t.filters.unregister('green-wash'); - filterActive = false; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const stateStr = filterActive ? 'ACTIVE' : 'INACTIVE'; - - drawText('FILTERS.UNREGISTER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DISPOSE CUSTOM FILTER', x, y++, 100, 220, 255); - drawText('Removes registered custom shader.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`FILTER STATE: ${stateStr}`, x, y++, 140, 190, 255); - drawText( - filterActive ? 'Click to unregister green-wash.' : 'Filter unregistered successfully.', - x, - y++, - 180, - 255, - 180 - ); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md index 4799a7f3..7531d989 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md @@ -22,92 +22,7 @@ glyph atlas, and used by [layering.TextmodeLayer](../../layering/classes/Textmod ## Example -```javascript -const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let customFont = null; -let fontReady = false; - -t.setup(async () => { - customFont = await t.loadFont(BESCII_URL); - fontReady = true; -}); - -t.draw(() => { - t.background(6, 14, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const active = fontReady && customFont ? customFont : t.font; - const glyphs = active.characters; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const gridX = Math.abs(x) % 6 === 0; - const gridY = Math.abs(y) % 6 === 0; - const wave = Math.sin(x * 0.2 + y * 0.2 + tm); - const norm = (wave + 1) * 0.5; - - const gIdx = Math.floor((Math.abs(x * y) + tm * 10) % (glyphs.length || 1)); - const glyphObj = glyphs[gIdx] || glyphs[0]; - const char = gridX || gridY ? '+' : glyphObj ? glyphObj.character : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - gridX || gridY ? 255 : Math.floor(40 + norm * 180), - Math.floor(180 + norm * 75), - gridX || gridY ? 180 : Math.floor(220 - norm * 100) - ); - t.cellColor(Math.floor(6 + norm * 12), Math.floor(18 + norm * 20), Math.floor(25 + norm * 25)); - t.char(char); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const status = fontReady ? 'FONT LOADED (BESCII)' : 'LOADING FONT...'; - const glyphCount = fontReady && customFont ? customFont.characters.length : t.font.characters.length; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ASYNC FONT LOADING', x, y++); - t.charColor(140, 160, 190); - t.print('loadFont(url) parses TrueType/WOFF', x, y++); - t.print('and constructs WebGL glyph atlas.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`STATUS: ${status}`, x, y++); - t.print(`GLYPHS LOADED: ${glyphCount}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Extends diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md index 509b73c1..916f618d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md @@ -29,82 +29,5 @@ Character-to-glyph lookup map. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 10); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.08; - const glyphs = t.font.characters; - const charMap = t.font.characterMap; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const stream = (y + Math.floor(tm * 4 + Math.sin(x * 0.3) * 6)) % (hh * 2 || 1); - const norm = Math.abs(stream) / (hh * 2 || 1); - - const charIdx = Math.floor((Math.abs(x) * 3 + norm * glyphs.length) % glyphs.length); - const charKey = glyphs[charIdx] ? glyphs[charIdx].character : ' '; - - const entry = charMap.get(charKey); - const unicode = entry ? entry.unicode : 32; - - t.push(); - t.translate(x, y); - t.charColor( - Math.floor(40 + (unicode % 180)), - Math.floor(240 - norm * 120), - Math.floor(100 + (unicode % 100)) - ); - t.cellColor(4, Math.floor(14 + norm * 24), 10); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const charMap = t.font.characterMap; - const mapSize = charMap.size; - const sampleEntry = charMap.get('@'); - const hexCode = sampleEntry ? `U+${sampleEntry.unicode.toString(16).toUpperCase().padStart(4, '0')}` : 'N/A'; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.CHARACTERMAP', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CHARACTER MAP LOOKUP', x, y++); - t.charColor(140, 160, 190); - t.print('Maps char strings to glyph metadata.', x, y++); - t.print('O(1) lookup for atlas resolution.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`MAP SIZE: ${mapSize} GLYPHS`, x, y++); - t.print(`GLYPH "@" UNICODE: ${hexCode}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md index 54ca2a97..1bc13cbc 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md @@ -29,82 +29,5 @@ readonly [`TextmodeGlyph`](../../../type-aliases/TextmodeGlyph.md)[] ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(8, 6, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const glyphs = t.font.characters; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const angle = Math.atan2(y, x) + tm; - const radius = Math.hypot(x, y); - const spiral = (angle * 3 + radius * 0.4) % (Math.PI * 2); - const val = (Math.sin(spiral) + 1) * 0.5; - - const gIdx = Math.floor((radius * 2 + angle * 4 + tm * 5) % (glyphs.length || 1)); - const glyphObj = glyphs[gIdx] || glyphs[0]; - const char = glyphObj ? glyphObj.character : '.'; - const unicode = glyphObj ? glyphObj.unicode : 32; - - t.push(); - t.translate(x, y); - t.charColor( - Math.floor(80 + (unicode % 160)), - Math.floor(140 + val * 100), - Math.floor(240 - (unicode % 120)) - ); - t.cellColor(Math.floor(10 + val * 20), Math.floor(12 + val * 20), Math.floor(30 + val * 30)); - t.char(char); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const glyphs = t.font.characters; - const sampleIdx = Math.floor(t.frameCount * 0.05) % (glyphs.length || 1); - const sampleGlyph = glyphs[sampleIdx] || { character: ' ', unicode: 32 }; - const hexCode = `U+${sampleGlyph.unicode.toString(16).toUpperCase().padStart(4, '0')}`; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.CHARACTERS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: UNICODE GLYPH ARRAY', x, y++); - t.charColor(140, 160, 190); - t.print('Array of all font TextmodeGlyph objects.', x, y++); - t.print('Accesses character & unicode attributes.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL GLYPHS: ${glyphs.length}`, x, y++); - t.print(`SAMPLE "${sampleGlyph.character}": ${hexCode}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md index bf798fc9..d92a6acc 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md @@ -32,75 +32,5 @@ when the internal font parser changes. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(8, 10, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const glyphs = t.font.characters; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const chebyshev = Math.max(Math.abs(x), Math.abs(y)); - const wave = Math.sin(chebyshev * 0.4 - tm * 2); - const norm = (wave + 1) * 0.5; - - const angle = Math.atan2(y, x); - const gIdx = Math.floor(Math.abs(chebyshev * 0.8 - tm * 8 + angle * 3) % (glyphs.length || 1)); - const glyphObj = glyphs[gIdx] || glyphs[0]; - const char = glyphObj ? glyphObj.character : '.'; - const unicode = glyphObj ? glyphObj.unicode : 32; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(60 + (unicode % 160)), Math.floor(120 + norm * 120), Math.floor(240 - norm * 100)); - t.cellColor(Math.floor(8 + norm * 15), Math.floor(14 + norm * 20), Math.floor(28 + norm * 25)); - t.char(char); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const fontObj = t.font; - const totalGlyphs = fontObj.characters ? fontObj.characters.length : 0; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.FONT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ACTIVE FONT ACCESSOR', x, y++); - t.charColor(140, 160, 190); - t.print('Gets or sets active TextmodeFont.', x, y++); - t.print('Provides font atlas & glyph data.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL GLYPHS: ${totalGlyphs}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md index 1dd8db93..38393dbb 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md @@ -29,74 +29,5 @@ Font size used for the glyph atlas. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.02; - const glyphs = t.font.characters; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x, y); - const scaleRing = Math.floor(dist * 0.35 - tm * 2) % 5; - const norm = Math.abs(scaleRing) / 5; - - const gIdx = Math.floor(Math.abs(dist * 0.7 - tm * 10 + Math.sin(x * 0.3) * 4) % (glyphs.length || 1)); - const glyphObj = glyphs[gIdx] || glyphs[0]; - const char = glyphObj ? glyphObj.character : '.'; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(240 - norm * 150), Math.floor(160 + norm * 85), Math.floor(60 + norm * 180)); - t.cellColor(Math.floor(10 + norm * 20), Math.floor(18 + norm * 15), Math.floor(30 + norm * 25)); - t.char(char); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const sz = t.font.fontSize; - const dims = t.font.maxGlyphDimensions; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.FONTSIZE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: FONT SIZE METRIC ACCESSOR', x, y++); - t.charColor(140, 160, 190); - t.print('Configures font atlas raster size.', x, y++); - t.print('Determines pixel glyph resolution.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`FONT SIZE: ${sz} PX`, x, y++); - t.print(`CELL DIMS: ${dims.width} x ${dims.height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md index cb274db1..1ecbdbb5 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md @@ -29,77 +29,5 @@ Normalized glyph atlas framebuffer used by the ASCII shader. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(10, 8, 16); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - - const scanX = Math.sin(tm) * hw; - const scanY = Math.cos(tm * 0.7) * hh; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dBeam1 = Math.abs(x - scanX); - const dBeam2 = Math.abs(y - scanY); - const field = Math.exp(-dBeam1 * 0.2) + Math.exp(-dBeam2 * 0.2); - const norm = Math.min(1, field * 0.5); - - const idx = Math.floor(norm * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(Math.floor(40 + norm * 200), Math.floor(160 + norm * 95), Math.floor(240 - norm * 80)); - t.cellColor(Math.floor(10 + norm * 15), Math.floor(12 + norm * 20), Math.floor(28 + norm * 25)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const fb = t.font.framebuffer; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.FRAMEBUFFER', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ATLAS TEXTURE FRAMEBUFFER', x, y++); - t.charColor(140, 160, 190); - t.print('GLFramebuffer storing glyph atlas.', x, y++); - t.print('Sampled by WebGL ASCII resolve pass.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - if (fb) { - t.print(`ATLAS DIMS: ${fb.width}x${fb.height} PX`, x, y++); - } else { - t.print('ATLAS INITIALIZING...', x, y++); - } - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md index 5d2772f5..e58be092 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md @@ -34,73 +34,5 @@ Maximum glyph cell dimensions in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(8, 8, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const dims = t.font.maxGlyphDimensions; - - const boxW = Math.max(3, Math.floor(dims.width / 4)); - const boxH = Math.max(3, Math.floor(dims.height / 4)); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const bx = Math.floor((x + hw) / boxW); - const by = Math.floor((y + hh) / boxH); - const norm = (Math.sin(bx * 0.5 + by * 0.5 + tm) + 1) * 0.5; - - const idx = Math.floor(norm * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(Math.floor(240 - norm * 140), Math.floor(140 + norm * 110), Math.floor(40 + norm * 200)); - t.cellColor(Math.floor(25 - norm * 15), Math.floor(10 + norm * 15), Math.floor(8 + norm * 20)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const dims = t.font.maxGlyphDimensions; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.MAXGLYPHDIMENSIONS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: MAX GLYPH CELL BOUNDS', x, y++); - t.charColor(140, 160, 190); - t.print('Maximum cell bounding dimensions.', x, y++); - t.print('Determines atlas cell slot size.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`MAX DIMS: ${dims.width} x ${dims.height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md index cec79477..a8c8268e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md @@ -29,71 +29,5 @@ Number of columns in the glyph atlas. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 12, 18); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const texCols = t.font.textureColumns || 16; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const colIndex = Math.abs(x) % texCols; - const normCol = colIndex / texCols; - const wave = Math.sin(colIndex * 0.5 + y * 0.15 + tm); - const norm = (wave + 1) * 0.5; - - const idx = Math.floor(norm * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(Math.floor(40 + normCol * 210), Math.floor(200 - normCol * 100), Math.floor(160 + norm * 80)); - t.cellColor(Math.floor(8 + normCol * 15), Math.floor(20 + norm * 20), Math.floor(30 + normCol * 20)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const texCols = t.font.textureColumns; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.TEXTURECOLUMNS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ATLAS TEXTURE COLUMNS', x, y++); - t.charColor(140, 160, 190); - t.print('Number of horizontal atlas slots.', x, y++); - t.print('Determines atlas UV column layout.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TEXTURE COLUMNS: ${texCols}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md index 4cb132a6..16d4dc44 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md @@ -29,71 +29,5 @@ Number of rows in the glyph atlas. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(16, 6, 12); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - const texRows = t.font.textureRows || 16; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const rowIndex = Math.abs(y) % texRows; - const normRow = rowIndex / texRows; - const wave = Math.cos(rowIndex * 0.5 + x * 0.15 + tm); - const norm = (wave + 1) * 0.5; - - const idx = Math.floor(norm * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(Math.floor(240 - normRow * 100), Math.floor(60 + normRow * 180), Math.floor(160 + norm * 80)); - t.cellColor(Math.floor(24 + normRow * 20), Math.floor(6 + norm * 15), Math.floor(15 + normRow * 15)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const texRows = t.font.textureRows; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.TEXTUREROWS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ATLAS TEXTURE ROWS', x, y++); - t.charColor(140, 160, 190); - t.print('Number of vertical atlas slots.', x, y++); - t.print('Determines atlas UV row layout.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TEXTURE ROWS: ${texRows}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md index 930c949e..d943b660 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md @@ -27,103 +27,7 @@ Dispose of all resources used by this font manager. ## Example -```javascript -const BESCII_URL = 'https://cdn.jsdelivr.net/gh/damianvila/font-bescii@main/fonts/v2.0/Bescii-Mono.ttf'; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let disposableFont = null; -let fontReady = false; -let isDisposed = false; - -t.setup(async () => { - disposableFont = await t.loadFont(BESCII_URL, false); - fontReady = true; -}); - -t.mousePressed(() => { - if (disposableFont && !isDisposed) { - disposableFont.dispose(); - isDisposed = true; - } -}); - -t.draw(() => { - t.background(16, 6, 10); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - const active = fontReady && !isDisposed && disposableFont ? disposableFont : t.font; - const glyphs = active.characters; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x, y); - const field = isDisposed ? Math.sin(x * 0.4 + y * 0.4 + tm) * 0.2 : Math.sin(dist * 0.3 - tm * 2); - const norm = (field + 1) * 0.5; - - const gIdx = Math.floor(Math.abs(dist * 0.6 + Math.atan2(y, x) * 4 - tm * 8) % (glyphs.length || 1)); - const glyphObj = glyphs[gIdx] || glyphs[0]; - const char = isDisposed ? '.' : glyphObj ? glyphObj.character : ' '; - - t.push(); - t.translate(x, y); - t.charColor( - isDisposed ? 90 : Math.floor(220 - norm * 140), - isDisposed ? 40 : Math.floor(100 + norm * 140), - isDisposed ? 50 : Math.floor(180 + norm * 75) - ); - t.cellColor( - isDisposed ? 18 : Math.floor(20 + norm * 15), - isDisposed ? 6 : Math.floor(6 + norm * 10), - isDisposed ? 8 : Math.floor(12 + norm * 20) - ); - t.char(char); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const stateText = isDisposed ? 'DISPOSED (RELEASED)' : 'ACTIVE (GLYPH ATLAS READY)'; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEFONT.DISPOSE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: FONT RESOURCE CLEANUP', x, y++); - t.charColor(140, 160, 190); - t.print('font.dispose() frees WebGL textures', x, y++); - t.print('and atlas framebuffer memory.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`STATUS: ${stateText}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO DISPOSE FONT', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Overrides diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md index 9772d37e..a0338af0 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md @@ -25,79 +25,7 @@ The native atlas stays at the authored tile resolution. ## Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const TILE_COLUMNS = 16; -const TILE_ROWS = 16; -const TILE_COUNT = TILE_COLUMNS * TILE_ROWS; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let tileset = null; - -function tilesetOptions() { - return { - source: T64_URL, - columns: TILE_COLUMNS, - rows: TILE_ROWS, - count: TILE_COUNT, - fontSize: 16, - }; -} - -t.setup(async () => { - tileset = await t.loadTileset(tilesetOptions()); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 7, 18); - if (!tileset) return; - const startX = -Math.floor(TILE_COLUMNS / 2); - const startY = -Math.floor(TILE_ROWS / 2); - for (let i = 0; i < TILE_COUNT; i++) { - t.push(); - t.translate(startX + (i % TILE_COLUMNS), startY + Math.floor(i / TILE_COLUMNS)); - t.char(i); - t.charColor(120 + i * 6, 220, 255 - i * 7); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODETILESET.CREATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ATLAS DATA', x, y++, 100, 220, 255); - drawText('T64 web tileset feeds glyphs.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('T64 READY', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Extends diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md index 0d0c2097..68804b6d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md @@ -34,93 +34,7 @@ Effective tile cell dimensions used by the layer grid. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const RAMP = ' .:-+*#@'; -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(8, 18, 38); - if (!tileset) return; - - const dims = tileset.cellDimensions; - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - - const ratio = dims.width / (dims.height || 1); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.abs(x * ratio) + Math.abs(y); - const ring = (Math.sin(dist * 0.4 - tm) + 1) * 0.5; - - const isCross = x === 0 || y === 0; - - if (ring > 0.45 || isCross) { - const val = isCross ? 1 : (ring - 0.45) / 0.55; - const idx = Math.floor(val * (RAMP.length - 1)); - - t.push(); - t.translate(x, y); - t.charColor( - isCross ? 0 : Math.floor(100 + val * 40), - isCross ? 230 : Math.floor(200 + val * 55), - isCross ? 255 : Math.floor(60 + val * 20) - ); - t.cellColor(4, Math.floor(14 + val * 20), Math.floor(30 + val * 20)); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - if (!tileset) return; - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const d = tileset.cellDimensions; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.CELLDIMENSIONS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: OPTICAL CALIBRATION RETICLE', x, y++); - t.charColor(140, 160, 190); - t.print('Measures tile width & height in px.', x, y++); - t.print('Scales reticle aspect ratio.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 80); - t.print(`TILE DIMS: ${d.width}x${d.height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Combined glyph cell dimensions in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md index 54e525c8..8eacc528 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md @@ -29,92 +29,7 @@ Effective tile cell height used by the layer grid. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(14, 4, 24); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const cH = tileset.cellHeight; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(y * (cH * 0.02) - tm * 2 + Math.sin(x * 0.25) * 2); - const norm = (wave + 1) * 0.5; - - const isCrest = Math.abs(wave) > 0.82; - const charIdx = Math.floor(Math.abs(y * 2 + Math.cos(x * 0.2 + tm * 2) * 6) % (chars.length || 1)); - const charKey = isCrest ? '=' : chars[charIdx] ? chars[charIdx].character : '-'; - - t.push(); - t.translate(x, y); - t.charColor( - isCrest ? 255 : Math.floor(180 + norm * 75), - isCrest ? 200 : Math.floor(40 + norm * 80), - isCrest ? 60 : Math.floor(140 + norm * 80) - ); - t.cellColor( - isCrest ? 35 : Math.floor(8 + norm * 12), - isCrest ? 10 : Math.floor(4 + norm * 10), - isCrest ? 40 : Math.floor(16 + norm * 20) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const height = tileset.cellHeight; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.CELLHEIGHT', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: VERTICAL RASTER OSCILLOGRAM', x, y++); - t.charColor(140, 160, 190); - t.print('Effective render cell height in px.', x, y++); - t.print('Controls vertical wave stride.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 200, 60); - t.print(`CELL HEIGHT: ${height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Height of each glyph cell in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md index c412ac16..fdb3933a 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md @@ -29,92 +29,7 @@ Effective tile cell width used by the layer grid. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(4, 16, 12); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.06; - const chars = tileset.characters; - const cW = tileset.cellWidth; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(x * (cW * 0.01) - tm * 3 + Math.sin(y * 0.25) * 3); - const norm = (wave + 1) * 0.5; - - const isBeam = Math.abs(wave) > 0.85; - const charIdx = Math.floor(Math.abs(x * 2 + Math.cos(y * 0.2 + tm * 3) * 6) % (chars.length || 1)); - const charKey = isBeam ? '=' : chars[charIdx] ? chars[charIdx].character : '-'; - - t.push(); - t.translate(x, y); - t.charColor( - isBeam ? 255 : Math.floor(40 + norm * 180), - isBeam ? 240 : Math.floor(220 - norm * 80), - isBeam ? 120 : Math.floor(140 + norm * 100) - ); - t.cellColor( - isBeam ? 24 : Math.floor(6 + norm * 10), - isBeam ? 35 : Math.floor(20 + norm * 20), - isBeam ? 20 : Math.floor(14 + norm * 15) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const width = tileset.cellWidth; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.CELLWIDTH', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: HORIZON WIDTH PULSE SCANNER', x, y++); - t.charColor(140, 160, 190); - t.print('Effective render cell width in px.', x, y++); - t.print('Controls horizontal column stride.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`CELL WIDTH: ${width} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Width of each glyph cell in pixels. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md index 0ccfff41..ab2fbd88 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md @@ -29,92 +29,7 @@ Character-to-glyph lookup map for the tileset. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -const KEYS = '@#$%&*<>[]{}~+=-'; -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(4, 8, 6); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.06; - - const map = tileset.characterMap; - - for (let x = -hw; x <= hw; x++) { - const dropSpeed = (Math.abs(x * 17) % 5) + 2; - const dropY = Math.floor((tm * dropSpeed + Math.abs(x * 11)) % (t.grid.rows + 10)) - hh; - - for (let y = -hh; y <= hh; y++) { - const distFromHead = dropY - y; - if (distFromHead >= 0 && distFromHead < 12) { - const charStr = KEYS[Math.abs(x * 3 + y) % KEYS.length]; - const hasMapKey = map ? map.has(charStr) : false; - const isHead = distFromHead === 0; - - t.push(); - t.translate(x, y); - t.charColor( - isHead ? 255 : 80, - isHead ? 255 : Math.floor(220 - distFromHead * 15), - isHead ? 200 : Math.floor(60 - distFromHead * 4) - ); - t.cellColor(4, isHead ? 40 : 12, 8); - t.char(hasMapKey ? charStr : '.'); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - if (!tileset) return; - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const mapSize = tileset.characterMap ? tileset.characterMap.size : 0; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.CHARACTERMAP', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SYMBOLIC CIPHER RAIN', x, y++); - t.charColor(140, 160, 190); - t.print('Queries characterMap key lookups.', x, y++); - t.print('Maps glyph symbols to atlas indices.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(120, 255, 40); - t.print(`MAP SIZE: ${mapSize} ENTRIES`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Lookup table from character string to glyph entry. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md index 574e6eca..085fa249 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md @@ -29,98 +29,7 @@ readonly [`TextmodeGlyph`](../../../type-aliases/TextmodeGlyph.md)[] ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(10, 10, 18); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const chars = tileset.characters; - const cursorIdx = Math.floor(t.frameCount * 0.1) % (chars.length || 1); - - const gridCols = 16; - const gridRows = 16; - const startX = -Math.floor(gridCols / 2); - const startY = -Math.floor(gridRows / 2); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const col = x - startX; - const row = y - startY; - - let charKey = ' '; - let isActive = false; - - if (col >= 0 && col < gridCols && row >= 0 && row < gridRows) { - const tileIndex = row * gridCols + col; - const glyphObj = chars[tileIndex]; - charKey = glyphObj ? glyphObj.character : ' '; - isActive = tileIndex === cursorIdx; - } - - t.push(); - t.translate(x, y); - t.charColor(isActive ? 255 : 120, isActive ? 220 : 180, isActive ? 100 : 240); - t.cellColor(isActive ? 40 : 12, isActive ? 30 : 12, isActive ? 10 : 24); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const chars = tileset.characters; - const cursorIdx = Math.floor(t.frameCount * 0.1) % (chars.length || 1); - const sampleObj = chars[cursorIdx] || { character: ' ', unicode: 32 }; - const hexCode = `U+${sampleObj.unicode.toString(16).toUpperCase().padStart(4, '0')}`; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.CHARACTERS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: FULL TILESET GLYPH CATALOG', x, y++); - t.charColor(140, 160, 190); - t.print('Array of all tileset TextmodeGlyph items.', x, y++); - t.print('Traverses full 256-tile catalog.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`TOTAL TILES: ${chars.length}`, x, y++); - t.print(`ACTIVE TILE: ${hexCode}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Ordered glyph entries available in this atlas. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md index de9f7430..c33dba3f 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md @@ -29,93 +29,7 @@ Number of columns in the normalized glyph atlas. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(4, 18, 26); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const numCols = tileset.columns; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const colIndex = Math.abs(x) % numCols; - const colWave = Math.sin(colIndex * ((Math.PI * 2) / numCols) + tm * 2.5 + Math.cos(y * 0.15) * 1.5); - const norm = (colWave + 1) * 0.5; - - const isPeak = Math.abs(colWave) > 0.85; - const charIdx = Math.floor(Math.abs(colIndex * 16 + y + tm * 10) % (chars.length || 1)); - const charKey = isPeak ? '#' : chars[charIdx] ? chars[charIdx].character : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isPeak ? 255 : Math.floor(20 + norm * 160), - isPeak ? 255 : Math.floor(180 + norm * 75), - isPeak ? 200 : Math.floor(140 + (colIndex / numCols) * 115) - ); - t.cellColor( - isPeak ? 15 : Math.floor(4 + norm * 10), - isPeak ? 45 : Math.floor(16 + norm * 20), - isPeak ? 50 : Math.floor(20 + norm * 25) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const cols = tileset.columns; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.COLUMNS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: 16-CHANNEL SPECTRUM MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('Partitions atlas into column bands.', x, y++); - t.print('Drives column phase offset wave.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(0, 240, 180); - t.print(`ATLAS COLUMNS: ${cols}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Number of glyph columns in the atlas texture. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md index b9a3712d..84a422df 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md @@ -29,77 +29,5 @@ Tileset atlas framebuffer backing this glyph atlas. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const TILE_COLUMNS = 16; -const TILE_ROWS = 16; -const TILE_COUNT = TILE_COLUMNS * TILE_ROWS; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let tileset = null; - -function tilesetOptions() { - return { - source: T64_URL, - columns: TILE_COLUMNS, - rows: TILE_ROWS, - count: TILE_COUNT, - fontSize: 16, - }; -} - -t.setup(async () => { - tileset = await t.loadTileset(tilesetOptions()); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 7, 18); - if (!tileset) return; - const startX = -Math.floor(TILE_COLUMNS / 2); - const startY = -Math.floor(TILE_ROWS / 2); - for (let i = 0; i < TILE_COUNT; i++) { - t.push(); - t.translate(startX + (i % TILE_COLUMNS), startY + Math.floor(i / TILE_COLUMNS)); - t.char(i); - t.charColor(120 + i * 6, 220, 255 - i * 7); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODETILESET.FONTFRAMEBUFFER', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ATLAS DATA', x, y++, 100, 220, 255); - drawText('T64 web tileset feeds glyphs.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const ready = Boolean(tileset.fontFramebuffer); - drawText(`GLYPH ATLAS FRAMEBUFFER: ${ready}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md index b40ed053..ad4e937e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md @@ -29,93 +29,5 @@ Effective font size used to scale tileset cells. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(6, 6, 16); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - const chars = tileset.characters; - - const cx = -0.7 + Math.sin(tm) * 0.1; - const cy = 0.27015 + Math.cos(tm * 0.7) * 0.05; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - let zx = (x / hw) * 1.5; - let zy = (y / hh) * 1.5; - let iter = 0; - for (let i = 0; i < 16; i++) { - if (zx * zx + zy * zy > 4) break; - const xtemp = zx * zx - zy * zy + cx; - zy = 2 * zx * zy + cy; - zx = xtemp; - iter++; - } - const norm = iter / 16; - - const charIdx = Math.floor(Math.abs(norm * chars.length + tm * 8) % (chars.length || 1)); - const charKey = chars[charIdx] ? chars[charIdx].character : ' '; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(255 - norm * 180), Math.floor(100 + norm * 155), Math.floor(60 + norm * 195)); - t.cellColor(Math.floor(8 + norm * 20), Math.floor(6 + norm * 15), Math.floor(20 + norm * 20)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const sz = tileset.fontSize; - const dims = tileset.cellDimensions; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.FONTSIZE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: JULIA FRACTAL SAMPLING', x, y++); - t.charColor(140, 160, 190); - t.print('Configures output cell render scale.', x, y++); - t.print('Does not alter native source tile size.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`FONT SIZE: ${sz} PX`, x, y++); - t.print(`CELL DIMS: ${dims.width} x ${dims.height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md index 66833cf3..7019b6f6 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md @@ -29,98 +29,7 @@ Normalized glyph atlas framebuffer used by the ASCII shader. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(4, 16, 10); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const sweepAngle = (tm * 2) % (Math.PI * 2); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x, y); - const angle = (Math.atan2(y, x) + Math.PI * 2) % (Math.PI * 2); - const diff = (sweepAngle - angle + Math.PI * 2) % (Math.PI * 2); - - const isRadarLine = diff < 0.15; - const isTrail = diff < 1.2; - const norm = isTrail ? 1 - diff / 1.2 : 0; - - const charIdx = Math.floor(Math.abs(dist * 0.8 + tm * 6) % (chars.length || 1)); - const charKey = isRadarLine ? '@' : isTrail ? (chars[charIdx] ? chars[charIdx].character : '#') : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isRadarLine ? 255 : Math.floor(40 + norm * 180), - isRadarLine ? 255 : Math.floor(100 + norm * 155), - isRadarLine ? 150 : Math.floor(40 + norm * 80) - ); - t.cellColor( - isRadarLine ? 35 : Math.floor(4 + norm * 20), - isRadarLine ? 45 : Math.floor(16 + norm * 24), - isRadarLine ? 20 : Math.floor(10 + norm * 15) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const fb = tileset.framebuffer; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.FRAMEBUFFER', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: REPACKED GPU ATLAS RADAR', x, y++); - t.charColor(140, 160, 190); - t.print('GLFramebuffer containing GPU texture.', x, y++); - t.print('Contains repacked tileset atlas data.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - if (fb) { - t.print(`TEXTURE DIMS: ${fb.width} x ${fb.height} PX`, x, y++); - } - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Framebuffer containing the atlas texture data. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md index 5973dfd5..24672fdf 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md @@ -34,90 +34,5 @@ Effective tile dimensions used by the layer grid. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(8, 24, 48); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const maxDims = tileset.maxGlyphDimensions; - - const boundW = Math.max(3, Math.floor(maxDims.width * 0.6)); - const boundH = Math.max(3, Math.floor(maxDims.height * 0.6)); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const relX = Math.abs(x) % (boundW + 4); - const relY = Math.abs(y) % (boundH + 4); - - const isEdgeX = relX === boundW; - const isEdgeY = relY === boundH; - const isVertex = isEdgeX && isEdgeY; - const isWire = isEdgeX || isEdgeY; - - const charIdx = Math.floor(Math.abs(x * 2 + y * 2 + tm * 6) % (chars.length || 1)); - const charKey = isVertex ? '+' : isWire ? (chars[charIdx] ? chars[charIdx].character : '#') : ' '; - - if (isWire) { - t.push(); - t.translate(x, y); - t.charColor(isVertex ? 255 : 40, isVertex ? 255 : 240, isVertex ? 255 : 140); - t.cellColor(isVertex ? 40 : 12, isVertex ? 50 : 28, isVertex ? 30 : 20); - t.char(charKey); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const maxDims = tileset.maxGlyphDimensions; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.MAXGLYPHDIMENSIONS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CAD CALIPER GRID STAGING', x, y++); - t.charColor(140, 160, 190); - t.print('Bounding box of largest atlas tile.', x, y++); - t.print('Establishes max tile cell bounds.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(40, 240, 140); - t.print(`MAX BOUNDS: ${maxDims.width} x ${maxDims.height} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md index 21b3041d..d07a1ae1 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md @@ -34,92 +34,5 @@ Authored tile dimensions from the source tileset in pixels. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(10, 10, 16); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const nDims = tileset.nativeCellDimensions; - - const lensX = Math.sin(tm) * 14; - const lensY = Math.cos(tm * 0.7) * 9; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dLens = Math.hypot(x - lensX, y - lensY); - const inLens = dLens < 8; - const isRing = Math.abs(dLens - 8) < 0.8; - - const scale = inLens ? nDims.width / 4 : 1; - const charIdx = Math.floor(Math.abs(x * scale + y * scale + tm * 8) % (chars.length || 1)); - const charKey = isRing ? '+' : chars[charIdx] ? chars[charIdx].character : ' '; - - t.push(); - t.translate(x, y); - t.charColor( - isRing ? 255 : inLens ? 100 : 70, - isRing ? 220 : inLens ? 240 : 120, - isRing ? 100 : inLens ? 180 : 160 - ); - t.cellColor(isRing ? 30 : inLens ? 22 : 8, isRing ? 20 : inLens ? 14 : 6, isRing ? 10 : inLens ? 18 : 10); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const nDims = tileset.nativeCellDimensions; - const cellDims = tileset.cellDimensions; - const scaleFactor = (cellDims.height / (nDims.height || 1)).toFixed(2); - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.NATIVECELLDIMENSIONS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SWEEPING LENS RETICLE PASS', x, y++); - t.charColor(140, 160, 190); - t.print('Native pixel dimensions in source sheet.', x, y++); - t.print('Compared against effective render size.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`NATIVE SIZE : ${nDims.width} x ${nDims.height} PX`, x, y++); - t.print(`SCALE RATIO : ${scaleFactor}X`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md index 4e618895..6fa69c18 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md @@ -29,94 +29,7 @@ Number of rows in the normalized glyph atlas. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(24, 10, 16); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const numRows = tileset.rows; - - for (let y = -hh; y <= hh; y++) { - const rowIndex = Math.abs(y) % numRows; - - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(rowIndex * 0.4 + x * 0.12 - tm * 2); - const norm = (wave + 1) * 0.5; - - const isCrest = Math.abs(wave) > 0.82; - const charIdx = Math.floor(Math.abs(rowIndex * 16 + x + tm * 8) % (chars.length || 1)); - const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isCrest ? 255 : Math.floor(180 + norm * 60), - isCrest ? 210 : Math.floor(90 + norm * 90), - isCrest ? 90 : Math.floor(40 + norm * 60) - ); - t.cellColor( - isCrest ? 45 : Math.floor(12 + norm * 15), - isCrest ? 20 : Math.floor(4 + norm * 10), - isCrest ? 10 : Math.floor(8 + norm * 10) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const numRows = tileset.rows; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.ROWS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: SEISMIC GEOLOGICAL STRATA', x, y++); - t.charColor(140, 160, 190); - t.print('Maps tileset atlas row count.', x, y++); - t.print('Structures horizontal grid strata.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 210, 90); - t.print(`ATLAS ROWS: ${numRows}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + Number of glyph rows in the atlas texture. diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md index dfdbe7fa..21b2a383 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md @@ -29,90 +29,5 @@ Number of columns in the repacked tileset atlas. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(4, 18, 24); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const texCols = tileset.textureColumns; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const colIdx = Math.abs(x) % (texCols || 1); - const ripple = Math.sin(y * 0.2 + colIdx * 0.4 - tm * 2.5); - const norm = (ripple + 1) * 0.5; - - const isCrest = Math.abs(ripple) > 0.85; - const charIdx = Math.floor(Math.abs(colIdx * 16 + y + tm * 8) % (chars.length || 1)); - const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : ':'; - - t.push(); - t.translate(x, y); - t.charColor( - isCrest ? 255 : Math.floor(40 + norm * 180), - isCrest ? 255 : Math.floor(200 - norm * 80), - isCrest ? 180 : Math.floor(60 + (colIdx / texCols) * 120) - ); - t.cellColor( - isCrest ? 20 : Math.floor(4 + norm * 10), - isCrest ? 45 : Math.floor(16 + norm * 20), - isCrest ? 40 : Math.floor(20 + norm * 20) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const texCols = tileset.textureColumns; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.TEXTURECOLUMNS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ATLAS COLUMN STRIDE WAVE', x, y++); - t.charColor(140, 160, 190); - t.print('Horizontal texture column count.', x, y++); - t.print('Defines GPU atlas texture stride.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(0, 255, 180); - t.print(`TEXTURE COLUMNS: ${texCols}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md index 4085ab58..d51d948f 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md @@ -29,91 +29,5 @@ Number of rows in the repacked tileset atlas. ### Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let tileset = null; - -t.setup(async () => { - tileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); -}); - -t.draw(() => { - t.background(20, 8, 16); - if (!tileset) return; - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const chars = tileset.characters; - const texRows = tileset.textureRows; - - for (let y = -hh; y <= hh; y++) { - const rowIdx = Math.abs(y) % (texRows || 1); - - for (let x = -hw; x <= hw; x++) { - const wave = Math.sin(rowIdx * 0.4 + x * 0.15 - tm * 2); - const norm = (wave + 1) * 0.5; - - const isCrest = Math.abs(wave) > 0.82; - const charIdx = Math.floor(Math.abs(rowIdx * 16 + x + tm * 8) % (chars.length || 1)); - const charKey = isCrest ? '*' : chars[charIdx] ? chars[charIdx].character : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isCrest ? 255 : Math.floor(200 + norm * 55), - isCrest ? 220 : Math.floor(80 + norm * 120), - isCrest ? 100 : Math.floor(20 + norm * 40) - ); - t.cellColor( - isCrest ? 45 : Math.floor(14 + norm * 16), - isCrest ? 15 : Math.floor(4 + norm * 10), - isCrest ? 10 : Math.floor(8 + norm * 10) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - if (!tileset) return; - const texRows = tileset.textureRows; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.TEXTUREROWS', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ATLAS ROW STRATA SOUNDING', x, y++); - t.charColor(140, 160, 190); - t.print('Vertical texture row count.', x, y++); - t.print('Defines GPU atlas row structure.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(255, 140, 30); - t.print(`TEXTURE ROWS: ${texRows}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md index c5ce821a..096416f7 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md @@ -27,101 +27,7 @@ Dispose the tileset and release its shared atlas resources. ## Example -```javascript -const T64_URL = 'https://littlebitspace.com/resources/fonts/T64.png'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let disposableTileset = null; -let fontReady = false; -let isDisposed = false; - -t.setup(async () => { - disposableTileset = await t.loadTileset({ source: T64_URL, columns: 16, rows: 16, count: 256, fontSize: 16 }); - fontReady = true; -}); - -t.mousePressed(() => { - if (disposableTileset && !isDisposed) { - disposableTileset.dispose(); - isDisposed = true; - } -}); - -t.draw(() => { - t.background(16, 6, 10); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.05; - const activeChars = fontReady && !isDisposed && disposableTileset ? disposableTileset.characters : []; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x, y); - const wave = Math.sin(dist * 0.35 - tm * 2); - const norm = (wave + 1) * 0.5; - - const charIdx = Math.floor(Math.abs(dist * 0.6 + tm * 6) % (activeChars.length || 1)); - const glyphObj = activeChars[charIdx]; - const charKey = isDisposed ? '.' : glyphObj ? glyphObj.character : '#'; - - t.push(); - t.translate(x, y); - t.charColor( - isDisposed ? 90 : Math.floor(240 - norm * 140), - isDisposed ? 40 : Math.floor(100 + norm * 140), - isDisposed ? 50 : Math.floor(180 + norm * 75) - ); - t.cellColor( - isDisposed ? 18 : Math.floor(20 + norm * 15), - isDisposed ? 6 : Math.floor(6 + norm * 10), - isDisposed ? 8 : Math.floor(12 + norm * 20) - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const stateText = isDisposed ? 'DISPOSED (GPU MEMORY FREED)' : 'ACTIVE (GLYPH ATLAS READY)'; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODETILESET.DISPOSE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: GPU ATLAS DISSOLVE MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('tileset.dispose() releases WebGL GPU', x, y++); - t.print('textures and atlas framebuffer.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`STATUS: ${stateText}`, x, y++); - t.charColor(255, 200, 100); - t.print('CLICK CANVAS TO DISPOSE TILESET', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Overrides diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md index 97517780..8fdff5a2 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md @@ -32,66 +32,5 @@ Framebuffer containing this layer's rendered textmode output. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const layer = t.layers.add({ blendMode: 'screen' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.translate(x, y); - t.charColor(rgb[0], rgb[1], rgb[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -layer.draw(() => { - t.clear(); - t.push(); - t.rotateZ(t.frameCount * 2); - t.char('*'); - t.charColor(120, 220, 255); - t.rect(14, 8); - t.pop(); -}); - -t.draw(() => { - t.background(8, 10, 18); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const fb = layer.asciiFramebuffer; - - drawText('TEXTMODELAYER.ASCIIFRAMEBUFFER', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: READ ASCII OUTPUT', x, y++, [100, 220, 255]); - drawText('Samples the converted texture.', x, y++, [140, 160, 190]); - drawText('Center pixel updates each frame.', x, y++, [140, 160, 190]); - if (!fb) return; - - const pixels = fb.readPixels(0); - const index = (Math.floor(fb.height / 2) * fb.width + Math.floor(fb.width / 2)) * 4; - const rgb = `${pixels[index]}, ${pixels[index + 1]}, ${pixels[index + 2]}`; - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`RGB: ${rgb}`, x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md index bb24f72b..53f5250e 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md @@ -34,77 +34,5 @@ Returns `undefined` before the layer is initialized. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const sourceLayer = t.layers.add(); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -function drawCenteredText(text, y, rgb = [255, 255, 255]) { - drawText(text, -Math.floor(text.length / 2), y, rgb); -} - -sourceLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.03; - - t.push(); - t.rotateZ((time * 180) / Math.PI); - t.charColor(255, 180, 100); - t.char('#'); - t.rect(14, 1); - t.rect(1, 14); - t.pop(); -}); - -t.draw(() => { - t.background(6, 10, 22); - - const fb = sourceLayer.drawFramebuffer; - - if (fb) { - t.push(); - t.translate(0, 0); - t.image(fb, 24, 14); - t.pop(); - - drawCenteredText('INTERNAL DATA BUFFER', 10, [140, 220, 255]); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const fb = sourceLayer.drawFramebuffer; - - drawText('TEXTMODELAYER.DRAWFRAMEBUFFER', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: RAW DRAW BUFFER', x, y++, [100, 220, 255]); - drawText('Captures pre-ASCII drawing.', x, y++, [140, 160, 190]); - drawText('Image preview reads the buffer.', x, y++, [140, 160, 190]); - if (!fb) return; - - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`SIZE: ${fb.width} x ${fb.height}`, x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md index dfe6b212..0bf49d83 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md @@ -32,79 +32,5 @@ Font or tileset used by this layer. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const bigFontLayer = t.layers.add({ fontSize: 32, blendMode: 'additive' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); - t.pop(); -}); - -bigFontLayer.draw(() => { - t.clear(); - const font = bigFontLayer.font; - const chars = font.characters; - const time = t.frameCount * 0.02; - - const cols = 8; - const rows = 3; - - for (let r = 0; r < rows; r++) { - for (let c = 0; c < cols; c++) { - const idx = (r * cols + c + Math.floor(time * 10)) % chars.length; - const glyph = chars[idx]; - - t.push(); - t.translate(c - Math.floor(cols / 2), r - Math.floor(rows / 2)); - t.char(glyph.character); - t.charColor(120, 180, 255); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const baseSize = t.layers.base.font.fontSize; - const layerSize = bigFontLayer.font.fontSize; - - drawText('TEXTMODELAYER.FONT', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER FONT STATE', x, y++, [100, 220, 255]); - drawText('Base and overlay keep fonts apart.', x, y++, [140, 160, 190]); - drawText('Large font layer uses additive.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`BASE FONT: ${baseSize} PX`, x, y++, [140, 180, 255]); - drawText(`LAYER FONT: ${layerSize} PX`, x, y++, [255, 225, 140]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md index 10295fd1..7e04831d 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md @@ -29,66 +29,5 @@ Grid associated with this layer. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const densityLayer = t.layers.add({ fontSize: 8, blendMode: 'screen' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.translate(-10, 0); - t.charColor(100, 150, 255, 100); - t.char('+'); - t.rect(14, 10); - t.pop(); -}); - -densityLayer.draw(() => { - t.clear(); - - t.push(); - t.translate(20, 0); - t.charColor(255, 225, 140, 150); - t.char('+'); - t.rect(28, 20); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const g = densityLayer.grid; - - drawText('TEXTMODELAYER.GRID', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: INDEPENDENT GRID', x, y++, [100, 220, 255]); - drawText('Each layer gets its own grid.', x, y++, [140, 160, 190]); - drawText('Font size changes cell count.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`BASE: ${t.grid.cols} x ${t.grid.rows}`, x, y++, [140, 180, 255]); - drawText(`LAYER: ${g.cols} x ${g.rows}`, x, y++, [255, 225, 140]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md index 7e5cf6c6..93e750ab 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md @@ -31,59 +31,5 @@ Returns `0` before the layer is initialized. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const detailLayer = t.layers.add({ fontSize: 8 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.translate(0, 0); - t.char('|'); - t.charColor(120, 180, 255, 100); - t.rect(1, t.grid.rows); - t.pop(); -}); - -detailLayer.draw(() => { - t.clear(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const g = detailLayer.grid; - - drawText('TEXTMODELAYER.HEIGHT', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER PIXEL HEIGHT', x, y++, [100, 220, 255]); - drawText('Reports ASCII framebuffer height.', x, y++, [140, 160, 190]); - drawText('Finer font size gives more rows.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`${detailLayer.height} PIXELS`, x, y++, [140, 255, 180]); - drawText(`${g.rows} ROWS x ${g.cellHeight}PX`, x, y++, [120, 200, 255]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md index 3816790a..5b7dc748 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md @@ -31,62 +31,5 @@ Returns `undefined` before the layer is initialized. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const layer = t.layers.add({ fontSize: 16, blendMode: 'screen' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [220, 230, 255]) { - t.push(); - t.translate(x, y); - t.charColor(rgb[0], rgb[1], rgb[2]); - - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - - t.pop(); -} - -t.draw(() => { - t.background(5, 7, 18); -}); - -layer.draw(() => { - t.clear(); - t.push(); - t.rotateZ(t.frameCount * 1.5); - t.charColor(120, 205, 255); - t.rect(18, 8); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const ready = layer.texture === layer.asciiFramebuffer.textures[0]; - - drawText('TEXTMODELAYER.TEXTURE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: ASCII TEXTURE HANDLE', x, y++, [100, 220, 255]); - drawText('Exposes the composited texture.', x, y++, [140, 160, 190]); - drawText('Matches asciiFramebuffer tex 0.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(ready ? 'TEXTURE: READY' : 'TEXTURE: PENDING', x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md index 32c72095..37529e78 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md @@ -31,59 +31,5 @@ Returns `0` before the layer is initialized. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const detailLayer = t.layers.add({ fontSize: 8 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.translate(0, 0); - t.char('='); - t.charColor(120, 180, 255, 100); - t.rect(t.grid.cols, 1); - t.pop(); -}); - -detailLayer.draw(() => { - t.clear(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const g = detailLayer.grid; - - drawText('TEXTMODELAYER.WIDTH', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER PIXEL WIDTH', x, y++, [100, 220, 255]); - drawText('Reports ASCII framebuffer width.', x, y++, [140, 160, 190]); - drawText('A finer layer has more cells.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`${detailLayer.width} PIXELS`, x, y++, [140, 255, 180]); - drawText(`${g.cols} CELLS x ${g.cellWidth}PX`, x, y++, [120, 200, 255]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md index a534aa41..211be98f 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md @@ -21,14 +21,13 @@ blendMode(mode?): void | LayerBlendMode; Set or get this layer's blend mode. -Pass a [LayerBlendMode](../../../enumerations/LayerBlendMode.md) constant (e.g. `t.BLEND_ADDITIVE`) or a -legacy string (e.g. `'additive'` — deprecated). +Pass a [LayerBlendMode](../../../enumerations/LayerBlendMode.md) constant such as `t.BLEND_ADDITIVE`. ## Parameters | Parameter | Type | Description | | ------ | ------ | ------ | -| `mode?` | `string` \| [`LayerBlendMode`](../../../enumerations/LayerBlendMode.md) | Blend mode to apply. | +| `mode?` | [`LayerBlendMode`](../../../enumerations/LayerBlendMode.md) | Blend mode to apply. | ## Returns @@ -38,91 +37,5 @@ Current blend mode as a numeric [LayerBlendMode](../../../enumerations/LayerBlen ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const blendModes = [t.BLEND_ADDITIVE, t.BLEND_SCREEN, t.BLEND_OVERLAY, t.BLEND_DIFFERENCE, t.BLEND_MULTIPLY]; -const colors = [ - [255, 80, 150], - [80, 180, 255], - [255, 200, 80], - [150, 255, 120], - [200, 120, 255], -]; - -const layers = blendModes.map((mode) => t.layers.add({ blendMode: mode, opacity: 0.9 })); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.translate(x, y); - t.charColor(rgb[0], rgb[1], rgb[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -function drawCenteredText(text, y, rgb = [255, 255, 255]) { - drawText(text, -Math.floor(text.length / 2), y, rgb); -} - -t.draw(() => { - const time = t.frameCount * 0.02; - t.background(10, 15, 25); - - const { cols, rows } = t.grid; - - t.char('+'); - t.charColor(40, 50, 80); - t.rect(cols, rows); - - layers.forEach((layer, i) => { - layer.draw(() => { - t.clear(); - t.push(); - - const angle = (i / layers.length) * Math.PI * 2 + time; - const radius = 8 + Math.sin(time * 2) * 2; - t.translate(Math.cos(angle) * radius, Math.sin(angle) * radius); - - t.charColor(...colors[i]); - t.char('@'); - t.rect(14, 8); - - drawCenteredText(blendModes[i], 0, [255, 255, 255]); - - t.pop(); - }); - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const active = blendModes[Math.floor(t.frameCount / 80) % blendModes.length]; - - drawText('TEXTMODELAYER.BLENDMODE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: PER-LAYER BLENDING', x, y++, [100, 220, 255]); - drawText('Each layer composites differently.', x, y++, [140, 160, 190]); - drawText('Opacity is set per layer too.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`MODES: ${blendModes.length}`, x, y++, [140, 255, 180]); - drawText(`WATCH: ${active}`, x, y++, [120, 200, 255]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md index 7ad744cf..88007f9b 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md @@ -50,96 +50,5 @@ Set explicit camera parameters for this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let camX = 0; -const camY = 10; -const camZ = 42; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 18); - - const time = t.frameCount * 0.03; - camX = Math.sin(time) * 22; - - // Update layer camera - scene.camera(camX, camY, camZ, 0, 0, 0); -}); - -scene.draw(() => { - t.clear(); - t.pointLight([255, 200, 120], { x: 20, y: -15, z: 30 }); - - // Rotate center shape group - t.push(); - t.rotateY(t.frameCount * 1.5); - - // Center cube - t.push(); - t.char('#'); - t.charColor(120, 220, 255); - t.box(8, 8, 8); - t.pop(); - - // Left pillar - t.push(); - t.translate(-12, 0, 0); - t.char('H'); - t.charColor(255, 120, 120); - t.box(4, 12, 4); - t.pop(); - - // Right pillar - t.push(); - t.translate(12, 0, 0); - t.char('O'); - t.charColor(120, 255, 120); - t.box(4, 12, 4); - t.pop(); - - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const eyeStr = `Cam Eye : [${camX.toFixed(1)}, ${camY.toFixed(1)}, ${camZ.toFixed(1)}]`; - drawText('TEXTMODELAYER.CAMERA', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER CAMERA', x, y++, [100, 220, 255]); - drawText('Sets a 3D camera on one layer.', x, y++, [140, 160, 190]); - drawText('Base background stays flat.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(eyeStr, x, y++, [120, 255, 180]); - drawText('Target: [0.0, 0.0, 0.0]', x, y++, [200, 200, 200]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md index 217fa825..1de172b9 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md @@ -29,100 +29,5 @@ The created camera. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let camera; -let camX = 0; -const camY = 8; -const camZ = 46; - -t.setup(() => { - camera = scene.createCamera(); - scene.setCamera(camera); -}); - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 18); - - camX = Math.sin(t.frameCount * 0.03) * 22; - - // Move and aim the layer camera each frame - camera.setPosition(camX, camY, camZ); - camera.lookAt(0, 0, 0); -}); - -scene.draw(() => { - t.clear(); - t.pointLight([255, 200, 120], { x: 20, y: -15, z: 30 }); - - // Rotate center shape group - t.push(); - t.rotateY(t.frameCount * 1.5); - - // Center cube - t.push(); - t.char('#'); - t.charColor(120, 220, 255); - t.box(8, 8, 8); - t.pop(); - - // Left pillar - t.push(); - t.translate(-12, 0, 0); - t.char('H'); - t.charColor(255, 120, 120); - t.box(4, 12, 4); - t.pop(); - - // Right pillar - t.push(); - t.translate(12, 0, 0); - t.char('O'); - t.charColor(120, 255, 120); - t.box(4, 12, 4); - t.pop(); - - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - let y = -Math.floor(t.grid.rows / 2) + 3; - const x = -Math.floor(t.grid.cols / 2) + 3; - - const eyeStr = `Cam Eye : [${camX.toFixed(1)}, ${camY.toFixed(1)}, ${camZ.toFixed(1)}]`; - drawText('TEXTMODELAYER.CREATECAMERA', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: OWNED CAMERA', x, y++, [100, 220, 255]); - drawText('Creates a camera for this layer.', x, y++, [140, 160, 190]); - drawText('Then setCamera activates it.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(eyeStr, x, y++, [120, 255, 180]); - drawText('Target: [0.0, 0.0, 0.0]', x, y++, [200, 200, 200]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md index e907ce07..e3af5c3c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md @@ -33,79 +33,5 @@ Delete plugin-specific state from this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const layer = t.layers.add(); -const labelLayer = t.layers.add(); -const PLUGIN_NAME = 'monitor'; -let stateDeleted = false; -let latestAngle = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.mousePressed(() => { - if (layer.hasPluginState(PLUGIN_NAME)) { - layer.deletePluginState(PLUGIN_NAME); - stateDeleted = true; - } -}); - -layer.draw(() => { - t.clear(); - - if (!layer.hasPluginState(PLUGIN_NAME)) { - layer.setPluginState(PLUGIN_NAME, { angle: 0, resets: 0 }); - } - - const state = layer.getPluginState(PLUGIN_NAME); - - state.angle += 0.05; - latestAngle = state.angle; - - t.push(); - t.rotateZ((state.angle * 180) / Math.PI); - t.charColor(120, 180, 255); - t.char('#'); - t.rect(8, 4); - t.pop(); -}); - -t.draw(() => { - t.background(6, 10, 22); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const statusColor = stateDeleted ? [255, 180, 100] : [120, 255, 150]; - - drawText('TEXTMODELAYER.DELETEPLUGINSTATE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: DELETE PLUGIN STATE', x, y++, [100, 220, 255]); - drawText('Click clears the monitor state.', x, y++, [140, 160, 190]); - drawText('Draw recreates it next frame.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(stateDeleted ? 'STATE: RECREATED' : 'STATE: ACTIVE', x, y++, statusColor); - drawText(`ANGLE: ${latestAngle.toFixed(2)}`, x, y++, [180, 200, 220]); - stateDeleted = false; -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md index 2014db33..61ad23f2 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md @@ -35,88 +35,5 @@ The callback runs each frame and should contain this layer's drawing commands. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const backLayer = t.layers.add({ opacity: 0.6 }); -const effectLayer = t.layers.add({ blendMode: 'additive' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - for (let y = -4; y <= 4; y += 2) { - t.push(); - t.translate(0, y); - t.rect(t.grid.cols, 1); - t.pop(); - } - t.pop(); -}); - -backLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.03; - - // Floating data nodes circling the center - for (let i = 0; i < 6; i++) { - const angle = time + (i / 6) * Math.PI * 2; - const r = 10; - t.push(); - t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); - t.charColor(100, 150, 255); - t.char('o'); - t.point(); - t.pop(); - } -}); - -effectLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.05; - const pulse = 0.5 + 0.5 * Math.sin(time); - - // Central core pulsing shape - t.push(); - t.charColor(255, 100 + pulse * 155, 100); - t.char('#'); - t.rect(8, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.DRAW', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER DRAW CALLBACK', x, y++, [100, 220, 255]); - drawText('Base, back, and effect draw apart.', x, y++, [140, 160, 190]); - drawText('Each callback owns its buffer.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('LAYERS: BASE + 2', x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md index 1aaaf068..b32d5be9 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md @@ -51,87 +51,7 @@ Call this method within your layer's draw callback to apply effects. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const effectLayer = t.layers.add(); -const labelLayer = t.layers.add(); - -const filters = [ - { name: 'invert', params: undefined, label: 'INVERT' }, - { name: 'grayscale', params: 1.0, label: 'GRAYSCALE (1.0)' }, - { name: 'sepia', params: 0.8, label: 'SEPIA (0.8)' }, - { name: 'threshold', params: 0.5, label: 'THRESHOLD (0.5)' }, -]; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); - t.pop(); -}); - -effectLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.02; - - for (let i = 0; i < 8; i++) { - const angle = time + (i / 8) * Math.PI * 2; - const r = 8 + Math.sin(time * 2) * 2; - t.push(); - t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); - t.charColor(100 + i * 20, 255 - i * 10, 150 + i * 10); - t.char('#'); - t.point(); - t.pop(); - } - - const filterIdx = Math.floor(t.frameCount / 120) % (filters.length + 1); - - if (filterIdx < filters.length) { - const active = filters[filterIdx]; - effectLayer.filter(active.name, active.params); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const filterIdx = Math.floor(t.frameCount / 120) % (filters.length + 1); - const active = filterIdx < filters.length ? filters[filterIdx].label : 'NORMAL'; - - drawText('TEXTMODELAYER.FILTER', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER POST FILTERS', x, y++, [100, 220, 255]); - drawText('Only the effect layer changes.', x, y++, [140, 160, 190]); - drawText('Base grid remains unfiltered.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`ACTIVE: ${active}`, x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Call Signature diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md index f257c237..350e9257 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md @@ -37,74 +37,5 @@ Current font size when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const detailLayer = t.layers.add({ fontSize: 8, blendMode: 'screen' }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.translate(0, 0); - t.charColor(40, 50, 80); - t.char('#'); - t.rect(20, 10); - t.pop(); -}); - -detailLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.03; - - t.push(); - t.translate(0, -2); - t.charColor(255, 225, 140, 150); - t.char('.'); - - for (let i = 0; i < 40; i++) { - const angle = time + i * 0.2; - const r = 12 + Math.sin(time + i * 0.5) * 4; - t.push(); - t.translate(Math.round(Math.cos(angle) * r * 1.5), Math.round(Math.sin(angle) * r * 0.6)); - t.point(); - t.pop(); - } - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.FONTSIZE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: PER-LAYER RESOLUTION', x, y++, [100, 220, 255]); - drawText('Smaller font gives denser cells.', x, y++, [140, 160, 190]); - drawText('Layer grids update independently.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`BASE: ${t.layers.base.fontSize()} PX`, x, y++, [140, 180, 255]); - drawText(`DETAIL: ${detailLayer.fontSize()} PX`, x, y++, [255, 225, 140]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md index c4c89764..5668b0ee 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md @@ -41,89 +41,5 @@ Stored state, or `undefined` when not set. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const trackerLayer = t.layers.add(); -const labelLayer = t.layers.add(); -const PLUGIN_NAME = 'tracker'; -let latestX = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -trackerLayer.setPluginState(PLUGIN_NAME, { - x: 0, - speed: 0.1, - amplitude: 15, -}); - -trackerLayer.draw(() => { - t.clear(); - - const state = trackerLayer.getPluginState(PLUGIN_NAME); - - if (state) { - state.x += state.speed; - const xPos = Math.round(Math.cos(state.x) * state.amplitude); - latestX = xPos; - - t.push(); - t.translate(xPos, 0); - t.charColor(120, 200, 255); - t.char('#'); - t.point(); - - t.push(); - t.translate(0, 3); - t.char('^'); - t.charColor(60, 70, 100); - t.point(); - t.pop(); - t.pop(); - } -}); - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, 1); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const state = trackerLayer.getPluginState(PLUGIN_NAME); - const xText = latestX.toString().padStart(3, ' '); - - drawText('TEXTMODELAYER.GETPLUGINSTATE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: READ PLUGIN STATE', x, y++, [100, 220, 255]); - drawText('Persistent data drives motion.', x, y++, [140, 160, 190]); - drawText('The layer owns the stored object.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`X: ${xText}`, x, y++, [180, 200, 220]); - drawText(`SPEED: ${state.speed.toFixed(2)}`, x, y++, [180, 200, 220]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md index bd1e8bda..68811606 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md @@ -35,75 +35,5 @@ Check whether plugin-specific state exists on this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const layer = t.layers.add(); -const labelLayer = t.layers.add(); -const PLUGIN_NAME = 'module'; -let exists = false; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - if (t.frameCount % 120 === 0) { - if (layer.hasPluginState(PLUGIN_NAME)) { - layer.deletePluginState(PLUGIN_NAME); - } else { - layer.setPluginState(PLUGIN_NAME, { active: true }); - } - } - - exists = layer.hasPluginState(PLUGIN_NAME); - const statusColor = exists ? [120, 255, 150] : [255, 100, 100]; - - t.push(); - t.translate(0, 0); - t.char(exists ? '#' : '.'); - t.charColor(exists ? statusColor : [60, 70, 100]); - t.rect(10, 5); - - t.push(); - t.translate(0, 0); - t.charColor(statusColor); - t.char('o'); - t.point(); - t.pop(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const statusColor = exists ? [120, 255, 150] : [255, 100, 100]; - - drawText('TEXTMODELAYER.HASPLUGINSTATE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: CHECK PLUGIN STATE', x, y++, [100, 220, 255]); - drawText('The module state toggles on/off.', x, y++, [140, 160, 190]); - drawText('hasPluginState returns a boolean.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(exists ? 'STATUS: CONNECTED' : 'STATUS: DISCONNECTED', x, y++, statusColor); - drawText(`HAS '${PLUGIN_NAME}': ${exists}`, x, y++, [140, 180, 255]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md index cfe9a5ee..136a9319 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md @@ -27,102 +27,5 @@ Hide this layer from rendering. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const signalLayer = t.layers.add({ blendMode: 'additive' }); -const labelLayer = t.layers.add(); -let isVisible = true; - -t.draw(() => { - t.background(6, 10, 22); - - if (t.frameCount % 120 === 0) { - if (isVisible) { - signalLayer.hide(); - } else { - signalLayer.show(); - } - isVisible = !isVisible; - } - - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - - t.push(); - t.charColor(30, 45, 75); - t.char('+'); - for (let y = -hh; y <= hh; y += 6) { - for (let x = -hw; x <= hw; x += 10) { - t.push(); - t.translate(x, y); - t.point(); - t.pop(); - } - } - t.pop(); -}); - -signalLayer.draw(() => { - t.clear(); - const tm = t.frameCount * 0.04; - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - - const trail = ['*', 'o', '.', ':']; - for (let i = 0; i < 16; i++) { - const angle = tm - i * 0.08; - const r = Math.min(hw, hh) * 0.5; - const px = Math.floor(Math.cos(angle) * r); - const py = Math.floor(Math.sin(angle) * (r * 0.6)); - const idx = Math.min(trail.length - 1, Math.floor((i / 16) * trail.length)); - - t.push(); - t.translate(px, py); - t.charColor(Math.floor(255 - i * 12), Math.floor(200 - i * 10), Math.floor(60 + i * 10)); - t.cellColor(30, 20, 5); - t.char(trail[idx]); - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODELAYER.HIDE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: CONTINUOUS RADAR STATE MASKING', x, y++); - t.charColor(140, 160, 190); - t.print('hide() pauses layer composition.', x, y++); - t.print('Background particle state advances.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - if (isVisible) { - t.charColor(140, 255, 180); - t.print('STATUS: VISIBLE (SIGNAL ON)', x, y++); - } else { - t.charColor(255, 120, 120); - t.print('STATUS: HIDDEN (STATE CONTINUES)', x, y++); - } - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md index 613190ed..e67c9d70 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md @@ -42,7 +42,7 @@ const t = textmode.create({ fontSize: 16, }); -const detailedLayer = t.layers.add({ blendMode: 'screen' }); +const detailedLayer = t.layers.add({ blendMode: t.BLEND_SCREEN }); const labelLayer = t.layers.add(); function drawText(text, x, y, rgb = [255, 255, 255]) { diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md index 0c2bfe0c..df1206d7 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md @@ -35,96 +35,5 @@ The loaded TextmodeTileset. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const tilesLayer = t.layers.add(); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(async () => { - await tilesLayer.loadTileset({ - source: 'https://littlebitspace.com/resources/fonts/T64.png', - columns: 16, - rows: 16, - count: 256, - }); - - // Use authored colors from the tileset PNG - tilesLayer.useTileColors(true); -}); - -t.draw(() => { - t.background(6, 10, 22); -}); - -tilesLayer.draw(() => { - t.clear(); - - const font = tilesLayer.font; - if (!font || font.characters.length === 0) return; - - const time = t.frameCount * 0.04; - const activeTile = Math.floor(time) % font.characters.length; - - const cols = 16; - const startX = -Math.floor(cols / 2); - const startY = -4; - - // Draw all tiles in a grid - for (let i = 0; i < font.characters.length; i++) { - const col = i % cols; - const row = Math.floor(i / cols); - t.push(); - t.translate(startX + col, startY + row); - t.char(i); - - // Highlight the currently cycled tile - if (i === activeTile) { - t.charColor(255, 255, 100); - } - - t.point(); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const font = tilesLayer.font; - const count = font ? font.characters.length : 0; - - drawText('TEXTMODELAYER.LOADTILESET', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LOAD TILESET', x, y++, [100, 220, 255]); - drawText('Loads bitmap glyphs into a layer.', x, y++, [140, 160, 190]); - drawText('Tile colors are authored in PNG.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`TILES LOADED: ${count}`, x, y++, [120, 255, 180]); - drawText('SOURCE: T64 PNG, 16 x 16', x, y++, [160, 160, 160]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md index 40a5fdfe..a4a339f5 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md @@ -44,96 +44,5 @@ Update this layer camera's target and optional up vector. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let targetX = 0; -let targetY = 0; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 18); - - targetX = Math.sin(t.frameCount * 0.04) * 12; - targetY = Math.cos(t.frameCount * 0.03) * 7; - - // Camera stays fixed — only the look target moves - scene.camera(0, 0, 46); - scene.lookAt(targetX, targetY, 0); -}); - -scene.draw(() => { - t.clear(); - - // Static reference pillars spread around the scene - t.push(); - t.translate(-16, 4, -10); - t.char('H'); - t.charColor(100, 130, 200); - t.box(5, 14, 5); - t.pop(); - - t.push(); - t.translate(16, 4, -10); - t.char('H'); - t.charColor(100, 130, 200); - t.box(5, 14, 5); - t.pop(); - - t.push(); - t.translate(0, 8, -18); - t.char('+'); - t.charColor(80, 100, 160); - t.box(30, 2, 2); - t.pop(); - - // Moving glowing target — the camera tracks this - t.push(); - t.translate(targetX, targetY, 0); - t.char('*'); - t.charColor(255, 230, 80); - t.box(4, 4, 4); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const tgtStr = `Cam Target: [${targetX.toFixed(1)}, ${targetY.toFixed(1)}, 0.0]`; - - drawText('TEXTMODELAYER.LOOKAT', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: CAMERA TARGET', x, y++, [100, 220, 255]); - drawText('Camera eye stays fixed.', x, y++, [140, 160, 190]); - drawText('lookAt follows a moving target.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('Eye: [0.0, 0.0, 46.0]', x, y++, [200, 200, 200]); - drawText(tgtStr, x, y++, [120, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md index c4e589c7..ae711cf5 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md @@ -45,82 +45,5 @@ Current offset when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const offsetLayer = t.layers.add({ blendMode: 'additive' }); -const labelLayer = t.layers.add(); -let currentOffset = { x: 0, y: 0 }; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - const time = t.frameCount * 0.03; - const g = t.grid; - - const offX = Math.round(Math.cos(time) * (g.width * 0.25)); - const offY = Math.round(Math.sin(time * 0.7) * (g.height * 0.25)); - - currentOffset = { x: offX, y: offY }; - offsetLayer.offset(offX, offY); - - const targetGridX = Math.round(offX / g.cellWidth); - const targetGridY = Math.round(offY / g.cellHeight); - - t.push(); - t.charColor(60, 70, 100, 150); - t.char('.'); - t.line(0, 0, targetGridX, targetGridY); - t.pop(); - - t.push(); - t.charColor(100, 120, 150); - t.char('+'); - t.point(); - t.pop(); -}); - -offsetLayer.draw(() => { - t.clear(); - - t.push(); - t.charColor(255, 180, 100); - t.char('#'); - t.rect(7, 3); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.OFFSET', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: PIXEL OFFSET', x, y++, [100, 220, 255]); - drawText('Moves the layer during composite.', x, y++, [140, 160, 190]); - drawText('Drawing coordinates stay local.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`OFFSET X: ${currentOffset.x} PX`, x, y++, [255, 180, 100]); - drawText(`OFFSET Y: ${currentOffset.y} PX`, x, y++, [255, 180, 100]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md index ddd758e8..c4ad4ba0 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md @@ -35,89 +35,5 @@ Current opacity when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const pulseLayer = t.layers.add({ blendMode: 'additive' }); -const labelLayer = t.layers.add(); -let currentOpacity = 1; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -function drawMeter(value, x, y, rgb) { - const width = 20; - const activeBlocks = Math.round(value * width); - - t.push(); - t.translate(x, y); - for (let i = 0; i < width; i++) { - const active = i < activeBlocks; - const color = active ? rgb : [60, 70, 100]; - t.push(); - t.translate(i, 0); - t.char(active ? '|' : '.'); - t.charColor(color[0], color[1], color[2]); - t.point(); - t.pop(); - } - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - const time = t.frameCount * 0.04; - const opacity = 0.5 + 0.5 * Math.sin(time); - - currentOpacity = opacity; - pulseLayer.opacity(opacity); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); - t.pop(); -}); - -pulseLayer.draw(() => { - t.clear(); - - t.push(); - t.charColor(255, 140, 180); - t.char('#'); - t.rect(12, 6); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.OPACITY', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: LAYER ALPHA', x, y++, [100, 220, 255]); - drawText('Pulse layer fades in and out.', x, y++, [140, 160, 190]); - drawText('Opacity is clamped from 0 to 1.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawMeter(currentOpacity, x, y++, [255, 225, 140]); - drawText(`OPACITY: ${currentOpacity.toFixed(2)}`, x, y++, [255, 225, 140]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md index d8c6ec55..6664d401 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md @@ -34,88 +34,5 @@ Enable orthographic projection for this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ['.', ':', '=', '#', '%']; -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 22); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - t.push(); - t.translate(x, y); - t.charColor(20, 30, 55); - t.cellColor(6, 10, 22); - t.char('.'); - t.point(); - t.pop(); - } - } - scene.ortho(); - scene.camera(30, 24, 30); -}); - -scene.draw(() => { - t.clear(); - const tm = t.frameCount * 0.03; - t.push(); - t.ambientLight(25, 35, 60); - t.pointLight(255, 200, 140, Math.sin(tm) * 15, 20, 20); - - for (let x = -16; x <= 16; x += 8) { - for (let z = -16; z <= 16; z += 8) { - const norm = Math.sin(x * 0.2 + z * 0.2 + tm) * 0.5 + 0.5; - const h = Math.floor(norm * 10 + 4); - const idx = Math.min(RAMP.length - 1, Math.floor(norm * RAMP.length)); - - t.push(); - t.translate(x, h * 0.5, z); - t.charColor(Math.floor(40 + norm * 140), Math.floor(180 + norm * 60), Math.floor(220 - norm * 80)); - t.cellColor(10, 20, 38); - t.char(RAMP[idx]); - t.box(4, h, 4); - t.pop(); - } - } - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODELAYER.ORTHO', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ISOMETRIC ARCHITECTURAL MATRIX', x, y++); - t.charColor(140, 160, 190); - t.print('Enables orthographic layer projection.', x, y++); - t.print('Objects retain scale regardless of depth.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('PROJECTION: PARALLEL ORTHOGRAPHIC', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md index 0ccade4b..9ffab38d 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md @@ -38,95 +38,5 @@ Enable perspective projection for this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let fov = 60; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 18); - - // FOV oscillates between 20° (telephoto) and 100° (wide) - fov = 60 + Math.sin(t.frameCount * 0.025) * 40; - - scene.perspective(fov, 0.1, 256); - scene.camera(0, 0, 44); - scene.lookAt(0, 0, 0); -}); - -scene.draw(() => { - t.clear(); - t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); - - // Three columns at increasing depth to show perspective compression - const depths = [0, -12, -24]; - const colors = [ - [120, 200, 255], - [160, 220, 180], - [255, 180, 120], - ]; - - for (let i = 0; i < 3; i++) { - t.push(); - t.translate(0, 0, depths[i]); - t.char('#'); - t.charColor(colors[i][0], colors[i][1], colors[i][2]); - t.box(8, 8, 8); - t.pop(); - } - - // Floor grid for depth reference - t.push(); - t.char('.'); - t.charColor(40, 55, 80); - for (let x = -24; x <= 24; x += 8) { - t.line(x, 6, 4, x, 6, -32); - } - for (let z = 4; z >= -32; z -= 8) { - t.line(-24, 6, z, 24, 6, z); - } - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const fovStr = `FOV: ${fov.toFixed(1)} deg`; - drawText('TEXTMODELAYER.PERSPECTIVE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: PERSPECTIVE FOV', x, y++, [100, 220, 255]); - drawText('FOV changes depth compression.', x, y++, [140, 160, 190]); - drawText('Near/far clip the layer camera.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(fovStr, x, y++, [120, 255, 180]); - drawText('NEAR: 0.1 FAR: 256.0', x, y++, [200, 200, 200]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md index 22a7cecb..3ab9585b 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md @@ -27,97 +27,5 @@ Reset this layer to default auto camera behavior. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let useCustomCamera = true; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.draw(() => { - t.background(8, 10, 18); - - // Alternate every 150 frames so the contrast is clear - useCustomCamera = Math.floor(t.frameCount / 150) % 2 === 0; - - if (useCustomCamera) { - // Dramatic off-axis perspective with moving eye - const camX = Math.sin(t.frameCount * 0.02) * 18; - scene.camera(camX, -14, 42, 0, 0, 0); - } else { - // Discard custom camera — auto view is restored - scene.resetCamera(); - } -}); - -scene.draw(() => { - t.clear(); - t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); - - const positions = [ - [-12, 0, 0], - [0, 0, -12], - [12, 0, 0], - ]; - const colors = [ - [120, 200, 255], - [200, 160, 255], - [255, 180, 120], - ]; - - for (let i = 0; i < 3; i++) { - t.push(); - t.translate(positions[i][0], positions[i][1], positions[i][2]); - t.char('#'); - t.charColor(colors[i][0], colors[i][1], colors[i][2]); - t.box(7, 7, 7); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.RESETCAMERA', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: RESET LAYER CAMERA', x, y++, [100, 220, 255]); - - if (useCustomCamera) { - drawText('MODE: CUSTOM CAMERA', x, y++, [255, 200, 100]); - drawText('camera() override is active.', x, y++, [140, 160, 190]); - } else { - drawText('MODE: AUTO CAMERA', x, y++, [120, 255, 180]); - drawText('resetCamera restored default.', x, y++, [140, 160, 190]); - } - - drawText('------------------------------------', x, y++, [80, 100, 150]); - const remaining = 150 - (t.frameCount % 150); - drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [200, 200, 200]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md index 545af200..1a075fde 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md @@ -39,77 +39,5 @@ Current rotation in degrees when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scannerLayer = t.layers.add({ blendMode: 'additive' }); -const labelLayer = t.layers.add(); -let currentAngle = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - const time = t.frameCount * 1.5; - const angle = time % 360; - - currentAngle = angle; - scannerLayer.rotateZ(angle); - - t.push(); - t.charColor(60, 70, 100); - t.char('.'); - t.line(-15, 0, 15, 0); - t.line(0, -8, 0, 8); - t.pop(); -}); - -scannerLayer.draw(() => { - t.clear(); - - t.push(); - t.charColor(140, 180, 255, 200); - t.char('#'); - t.rect(20, 1); - t.pop(); - - t.push(); - t.translate(10, 0); - t.char('>'); - t.charColor(255, 225, 140); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODELAYER.ROTATEZ', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: COMPOSITE ROTATION', x, y++, [100, 220, 255]); - drawText('Layer output rotates around center.', x, y++, [140, 160, 190]); - drawText('Draw callback remains unrotated.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`ANGLE: ${currentAngle.toFixed(1)} DEG`, x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md index 281fbc05..04f9b9c7 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md @@ -33,100 +33,5 @@ Activate a camera for this layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const scene = t.layers.add(); -const labelLayer = t.layers.add(); - -let camA; -let camB; -let activeCam = 'A'; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(() => { - camA = scene.createCamera(); - camA.setPosition(-22, -8, 40).lookAt(0, 0, 0); - camB = scene.createCamera(); - camB.setPosition(22, 12, 36).lookAt(0, 0, 0); - scene.setCamera(camA); -}); - -t.draw(() => { - t.background(8, 10, 18); - const slot = Math.floor(t.frameCount / 150) % 2; - if (slot === 0 && activeCam !== 'A') { - scene.setCamera(camA); - activeCam = 'A'; - } else if (slot === 1 && activeCam !== 'B') { - scene.setCamera(camB); - activeCam = 'B'; - } -}); - -scene.draw(() => { - t.clear(); - t.pointLight([255, 210, 130], { x: -20, y: -25, z: 30 }); - const positions = [ - [-12, 0, 0], - [0, 0, -12], - [12, 0, 0], - ]; - const colors = [ - [120, 200, 255], - [200, 160, 255], - [255, 180, 120], - ]; - for (let i = 0; i < 3; i++) { - t.push(); - t.translate(positions[i][0], positions[i][1], positions[i][2]); - t.char('#'); - t.charColor(colors[i][0], colors[i][1], colors[i][2]); - t.box(7, 7, 7); - t.pop(); - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const isA = activeCam === 'A'; - drawText('TEXTMODELAYER.SETCAMERA', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: SWAP ACTIVE CAMERA', x, y++, [100, 220, 255]); - drawText('Two owned cameras alternate.', x, y++, [140, 160, 190]); - drawText('setCamera selects the view.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`ACTIVE: CAMERA ${activeCam}`, x, y++, isA ? [120, 200, 255] : [255, 180, 120]); - if (isA) { - drawText('EYE: [-22, -8, 40]', x, y++, [200, 200, 200]); - } else { - drawText('EYE: [22, 12, 36]', x, y++, [200, 200, 200]); - } - const remaining = 150 - (t.frameCount % 150); - drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [160, 160, 160]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md index e89c195d..04519f02 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md @@ -41,84 +41,5 @@ Plugins can use this to attach their own data to layer instances. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const moduleLayer = t.layers.add(); -const labelLayer = t.layers.add(); -const PLUGIN_NAME = 'core-data'; -let currentPower = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - moduleLayer.setPluginState(PLUGIN_NAME, { - power: 0, - sync: true, - id: 'CORE-A1', - }); -}); - -moduleLayer.draw(() => { - t.clear(); - const state = moduleLayer.getPluginState(PLUGIN_NAME); - - if (state) { - state.power = 0.5 + 0.5 * Math.sin(t.frameCount * 0.05); - currentPower = state.power; - - t.push(); - t.charColor(140, 220, 255); - t.char('#'); - const size = 4 + Math.round(state.power * 4); - t.rect(size * 2, size); - t.pop(); - } -}); - -t.draw(() => { - t.background(6, 10, 22); - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const state = moduleLayer.getPluginState(PLUGIN_NAME); - const load = Math.round(currentPower * 100); - - drawText('TEXTMODELAYER.SETPLUGINSTATE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: STORE PLUGIN STATE', x, y++, [100, 220, 255]); - drawText('Attaches data to a layer.', x, y++, [140, 160, 190]); - drawText('The object persists each frame.', x, y++, [140, 160, 190]); - if (!state) return; - - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`ID: ${state.id}`, x, y++, [180, 200, 220]); - drawText(`PWR LOAD: ${load}%`, x, y++, [140, 220, 255]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md index c80ea166..cfcaac76 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md @@ -27,81 +27,5 @@ Show this layer for rendering. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const displayLayer = t.layers.add({ visible: false, blendMode: 'additive' }); -const labelLayer = t.layers.add(); -let isVisible = false; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 10, 22); - - if (t.frameCount % 120 === 0) { - if (isVisible) { - displayLayer.hide(); - } else { - displayLayer.show(); - } - isVisible = !isVisible; - } - - t.push(); - t.charColor(40, 50, 80); - t.char('.'); - t.rect(t.grid.cols, t.grid.rows); - t.pop(); -}); - -displayLayer.draw(() => { - t.clear(); - const time = t.frameCount * 0.03; - - t.push(); - t.charColor(255, 180, 100); - t.char('#'); - t.rotateZ((time * 180) / Math.PI); - t.rect(12, 12); - t.pop(); - - t.push(); - t.charColor(255, 225, 140); - t.char('+'); - t.point(); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - const statusColor = isVisible ? [140, 255, 180] : [255, 100, 100]; - - drawText('TEXTMODELAYER.SHOW', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: SHOW HIDDEN LAYER', x, y++, [100, 220, 255]); - drawText('show() restores compositing.', x, y++, [140, 160, 190]); - drawText('hide() pauses visible output.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(isVisible ? 'LAYER: VISIBLE' : 'LAYER: HIDDEN', x, y++, statusColor); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md index 11ddab97..9f6a4896 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md @@ -39,100 +39,5 @@ Current tileset-color mode when called without arguments. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const tilesLayer = t.layers.add(); -const labelLayer = t.layers.add(); - -let useAuthored = false; - -function drawText(text, x, y, color = [200, 220, 255]) { - t.push(); - t.translate(x, y); - t.charColor(color[0], color[1], color[2]); - for (let i = 0; i < text.length; i++) { - t.char(text[i]); - t.point(); - t.translate(1, 0); - } - t.pop(); -} - -t.setup(async () => { - await tilesLayer.loadTileset({ - source: 'https://littlebitspace.com/resources/fonts/T64.png', - columns: 16, - rows: 16, - count: 256, - }); -}); - -t.draw(() => { - t.background(6, 10, 22); - useAuthored = Math.floor(t.frameCount / 150) % 2 === 0; - tilesLayer.useTileColors(useAuthored); -}); - -tilesLayer.draw(() => { - t.clear(); - - const font = tilesLayer.font; - if (!font || font.characters.length === 0) return; - - const cols = 16; - const rows = 8; - const startX = -Math.floor(cols / 2); - const startY = -3; - - for (let row = 0; row < rows; row++) { - for (let col = 0; col < cols; col++) { - const tileIndex = row * cols + col; - if (tileIndex >= font.characters.length) break; - - t.push(); - t.translate(startX + col, startY + row); - t.char(tileIndex); - const hue = (tileIndex / font.characters.length) * 360; - const r = Math.round(128 + 100 * Math.sin((hue * Math.PI) / 180)); - const g = Math.round(128 + 100 * Math.sin(((hue + 120) * Math.PI) / 180)); - const b = Math.round(128 + 100 * Math.sin(((hue + 240) * Math.PI) / 180)); - t.charColor(r, g, b); - - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - let y = -Math.floor(t.grid.rows / 2) + 3; - const x = -Math.floor(t.grid.cols / 2) + 3; - - drawText('TEXTMODELAYER.USETILECOLORS', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: TILESET COLOR SOURCE', x, y++, [100, 220, 255]); - - if (useAuthored) { - drawText('MODE: AUTHORED COLORS', x, y++, [255, 210, 100]); - drawText('Tile PNG colors show directly.', x, y++, [140, 160, 190]); - } else { - drawText('MODE: RECOLORED', x, y++, [120, 255, 180]); - drawText('charColor palette is applied.', x, y++, [140, 160, 190]); - } - - drawText('------------------------------------', x, y++, [80, 100, 150]); - const remaining = 150 - (t.frameCount % 150); - drawText(`SWITCH IN: ${remaining} FRAMES`, x, y++, [160, 160, 160]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md index 8c4a83ac..e7bd4629 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md @@ -29,75 +29,5 @@ readonly [`TextmodeLayer`](../../TextmodeLayer.md)[] ### Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); -const pigments = [ - [243, 114, 92], - [65, 205, 177], - [105, 127, 246], - [244, 196, 94], -]; -const curtains = pigments.map((color) => t.layers.add({ blendMode: 'screen', opacity: 0.64 })); -const labelLayer = t.layers.add(); - -function text(value, x, y, color = [220, 230, 245]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(...color); - t.print(value, x, y); - t.pop(); -} -function put(x, y, glyph, color) { - t.push(); - t.translate(x, y); - t.charColor(...color); - t.char(glyph); - t.point(); - t.pop(); -} -function curtain(index) { - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2), - f = t.frameCount * 0.026; - for (let y = -R; y <= R; y++) { - const spine = Math.sin(y * 0.13 + index * 1.8 + f) * (8 + index * 2) + Math.sin(y * 0.035 - f) * 7; - for (let width = -5; width <= 5; width += 2) { - const x = Math.round(spine + width + Math.sin(y * 0.31 + f * 2) * 2); - if (Math.abs(x) < C - 2 && (y + width + index) % 3 !== 0) - put(x, y, width === 0 ? '|' : ':', pigments[index]); - } - } -} - -curtains.forEach((layer, index) => - layer.draw(() => { - t.clear(); - curtain(index); - }) -); -t.draw(() => { - t.background(7, 8, 22); - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2), - f = t.frameCount * 0.018; - for (let x = -C; x <= C; x += 4) - for (let y = -R; y <= R; y += 3) if ((x * 3 + y) % 11 === 0) put(x, y, '.', [28, 36, 70]); - t.layers.all - .filter((layer) => layer !== labelLayer) - .forEach((layer, index) => { - layer.offset(Math.sin(f + index * 1.7) * 6, Math.cos(f * 1.4 + index) * 2); - layer.opacity(0.44 + 0.32 * (0.5 + 0.5 * Math.sin(f * 3 + index))); - }); -}); -labelLayer.draw(() => { - t.clear(); - const L = -Math.floor(t.grid.cols / 2), - T = -Math.floor(t.grid.rows / 2); - text('LAYERMANAGER.ALL', L + 3, T + 3, [100, 255, 140]); - text('------------------------------------', L + 3, T + 4, [80, 100, 150]); - text('THE WHOLE STACK DRIFTS TOGETHER', L + 3, T + 5, [100, 220, 255]); - text(`LIVE CURTAINS: ${t.layers.all.length - 1}`, L + 3, T + 6, [140, 255, 180]); -}); -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md index fcc6f3d3..e07769cf 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md @@ -35,95 +35,5 @@ The base layer cannot be removed or moved. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const base = t.layers.base; -const overlay = t.layers.add({ blendMode: 'screen', opacity: 0.85 }); -const labelLayer = t.layers.add(); - -base.draw(() => { - t.background(16, 8, 14); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const time = t.frameCount * 0.03; - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const v = Math.abs(Math.sin(x * 0.22) + Math.cos(y * 0.22) + Math.sin((x + y) * 0.08 + time)); - if (v > 0.4) { - const norm = Math.min(1, (v - 0.4) / 1.4); - const idx = Math.floor(norm * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(240, 130 + idx * 10, 50); - t.cellColor(28, 12, 22); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -overlay.draw(() => { - t.clear(); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const angle = t.frameCount * 0.025; - const cosA = Math.cos(angle); - const sinA = Math.sin(angle); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const d = Math.abs(-sinA * x + cosA * y); - if (d < 1.5) { - const intensity = 1 - d / 1.5; - const idx = Math.floor(intensity * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(40, 240, 160); - t.cellColor(8, 45, 30); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('LAYERMANAGER.BASE', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: ACCESSING BASE LAYER', x, y++); - t.charColor(140, 160, 190); - t.print('Accesses base layer via t.layers.base.', x, y++); - t.print('Base layer draws below user overlays.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('BASE LAYER ACTIVE: YES', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md index 15829987..a7456949 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md @@ -32,102 +32,5 @@ and any user-created layer via [TextmodeLayer.filter](../../TextmodeLayer/method ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const filteredLayer = t.layers.add({ blendMode: 'screen', opacity: 0.8 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -t.setup(async () => { - await t.layers.filters.register( - 'ripple', - `#version 300 es -precision highp float; -uniform sampler2D u_texture; -uniform float u_time; -uniform float u_amount; -in vec2 v_uv; -out vec4 fragColor; -void main() { - float d = length(v_uv - 0.5); - float w = sin(d * 8.0 - u_time) * u_amount; - vec2 uv = v_uv + vec2(w * cos(d * 3.0), w * sin(d * 3.0)); - fragColor = texture(u_texture, clamp(uv, 0.0, 1.0)); -}`, - { u_time: ['time', 0], u_amount: ['amount', 0.025] } - ); -}); - -t.draw(() => { - t.background(6, 10, 22); - - const tc = t.frameCount * 0.022; - for (let i = 0; i < 75; i++) { - const p = (i / 75) * Math.PI * 2; - const r = 3 + 6 * ((i % 8) / 8) + Math.sin(tc + i * 0.15) * 1.2; - const a = p + tc * 0.35 * ((i % 3) - 1); - const x = Math.round(Math.cos(a) * r * 1.5); - const y = Math.round(Math.sin(a) * r); - - t.push(); - t.translate(x, y); - t.charColor(30 + i * 0.8, 60 + i * 0.4, 110 + i * 0.3); - t.char('.'); - t.point(); - t.pop(); - } -}); - -filteredLayer.draw(() => { - t.clear(); - - const tc = t.frameCount * 0.028; - for (let i = 0; i < 60; i++) { - const p = (i / 60) * Math.PI * 2; - const r = 2 + 4 * ((i % 6) / 6) + Math.sin(tc * 0.8 + i * 0.22) * 1; - const a = p - tc * 0.5 * ((i % 3) + 1); - const x = Math.round(Math.cos(a) * r * 1.5); - const y = Math.round(Math.sin(a) * r); - const hue = Math.sin(a + tc) * 0.4 + 0.6; - - t.push(); - t.translate(x, y); - t.charColor(200 + hue * 55, 100 + hue * 70, 50 + hue * 40); - t.char('*'); - t.point(); - t.pop(); - } - - filteredLayer.filter('ripple', { time: tc * 2, amount: 0.022 }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - - drawText('LAYERMANAGER.FILTERS', left + 3, y++, [100, 255, 140]); - drawText('------------------------------------', left + 3, y++, [80, 100, 150]); - drawText('CONCEPT: GLOBAL FILTER MANAGER', left + 3, y++, [100, 220, 255]); - drawText('Registers a custom ripple filter.', left + 3, y++, [140, 160, 190]); - drawText('FILTER: ripple', left + 3, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md index 6554916f..ca1cdaaf 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md @@ -32,97 +32,5 @@ that will receive the current frame's composited result. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; -const waveLayer = t.layers.add({ blendMode: 'screen' }); -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(5, 10, 24); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.04; - - const lissX = Math.sin(tm * 1.3) * (hw * 0.6); - const lissY = Math.cos(tm * 0.9) * (hh * 0.6); - - for (let y = -hh; y <= hh; y++) { - for (let x = -hw; x <= hw; x++) { - const dist = Math.hypot(x - lissX, y - lissY); - const wave = (Math.sin(dist * 0.35 - tm * 2) + 1) * 0.5; - - if (wave > 0.5) { - const idx = Math.floor(((wave - 0.5) / 0.5) * (RAMP.length - 1)); - t.push(); - t.translate(x, y); - t.charColor(0, Math.floor(120 + wave * 135), 245); - t.cellColor(2, 12, 35); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -}); - -waveLayer.draw(() => { - t.clear(); - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const tm = t.frameCount * 0.03; - - for (let y = -hh; y <= hh; y += 2) { - for (let x = -hw; x <= hw; x += 2) { - const gridHarmonic = Math.sin(x * 0.2 + tm) * Math.cos(y * 0.2 - tm); - if (gridHarmonic > 0.4) { - t.push(); - t.translate(x, y); - t.charColor(255, 130, 40); - t.char('+'); - t.point(); - t.pop(); - } - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - const fb = t.layers.resultFramebuffer; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('LAYERMANAGER.RESULTFRAMEBUFFER', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: OSCILLOSCOPE FEEDBACK LENS', x, y++); - t.charColor(140, 160, 190); - t.print('Inspects composited WebGL framebuffer.', x, y++); - t.print('Reads pixel render target bounds.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - if (fb) { - t.charColor(255, 180, 40); - t.print(`FB BOUNDS: ${fb.width}x${fb.height} PX`, x, y++); - } - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md index 81dcf6bf..d25bfbe7 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md @@ -38,94 +38,5 @@ The created layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const RAMP = ' .:-=+*#%@'; - -const layer1 = t.layers.add({ blendMode: 'screen', opacity: 0.85 }); -const layer2 = t.layers.add({ blendMode: 'additive', opacity: 0.75 }); -const labelLayer = t.layers.add(); - -function drawField(fn, fg, bg, minV = 0.3) { - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - for (let y = -hh; y <= hh; y += 1) { - for (let x = -hw; x <= hw; x += 1) { - const v = fn(x, y); - if (v > minV) { - const idx = Math.min(RAMP.length - 1, Math.floor(((v - minV) / (1 - minV)) * RAMP.length)); - t.push(); - t.translate(x, y); - t.charColor(fg[0], fg[1], fg[2]); - t.cellColor(bg[0], bg[1], bg[2]); - t.char(RAMP[idx]); - t.point(); - t.pop(); - } - } - } -} - -t.draw(() => { - t.background(6, 10, 22); - const tm = t.frameCount * 0.02; - const f = (x, y) => (Math.sin(x * 0.08 + tm) + Math.cos(y * 0.1 + tm)) * 0.5 + 0.5; - drawField(f, [40, 70, 110], [10, 16, 32], 0.4); -}); - -layer1.draw(() => { - t.clear(); - const tm = t.frameCount * 0.03; - const f = (x, y) => Math.sin(x * 0.1 + y * 0.08 + tm) * Math.cos(x * 0.08 - y * 0.12 + tm * 0.8); - drawField(f, [240, 150, 40], [60, 30, 8], 0.25); -}); - -layer2.draw(() => { - t.clear(); - const tm = t.frameCount * 0.04; - const hw = Math.floor(t.grid.cols / 2); - const hh = Math.floor(t.grid.rows / 2); - const cx = Math.cos(tm) * (hw * 0.4); - const cy = Math.sin(tm * 0.8) * (hh * 0.4); - const f = (x, y) => - (Math.sin(Math.hypot(x - cx, y - cy) * 0.35 - tm * 1.5) + - Math.sin(Math.hypot(x + cx, y + cy) * 0.35 - tm * 1.5)) * - 0.5; - drawField(f, [40, 220, 200], [8, 50, 45], 0.3); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('LAYERMANAGER.ADD', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: GENERATIVE LAYERED FIELDS', x, y++); - t.charColor(140, 160, 190); - t.print('Adds user layers to composite fields.', x, y++); - t.print('Layers blend screen & additive passes.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print('USER LAYERS ADDED: 2', x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md index 4c5c0098..1d55b8e6 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md @@ -29,102 +29,5 @@ The base layer is not affected by this operation. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const REGIMES = [ - { name: 'RAIN', glyph: '|', rise: false, vel: 0.9, sway: 0, tint: [150, 190, 255] }, - { name: 'EMBERS', glyph: '*', rise: true, vel: 0.3, sway: 2, tint: [255, 170, 60] }, - { name: 'SNOW', glyph: '*', rise: false, vel: 0.14, sway: 2, tint: [225, 235, 255] }, -]; -let mode = 0; -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} -function put(x, y, glyph, rgb) { - t.push(); - t.translate(x, y); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.char(glyph); - t.point(); - t.pop(); -} -const hash = (x, y) => Math.abs(Math.sin(x * 127.1 + y * 311.7) * 43758.5453) % 1; - -function drawHud() { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('LAYERMANAGER.CLEAR', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: WIPE USER LAYERS', x, y++, [100, 220, 255]); - drawText('clear() rebuilds the stack.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`REGIME: ${REGIMES[mode % 3].name}`, x, y++, [140, 255, 180]); -} - -function weatherLayer(near) { - const layer = t.layers.add({ blendMode: t.BLEND_ADDITIVE, opacity: near ? 0.9 : 0.5 }); - - layer.draw(() => { - t.clear(); - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - const rg = REGIMES[mode % REGIMES.length]; - const rgb = near ? rg.tint : rg.tint.map((c) => Math.floor(c * 0.5)); - const f = t.frameCount; - - for (let i = 0; i < (near ? 34 : 60); i++) { - const h = hash(i, near ? 3 : 7); - const travel = (h * t.grid.rows + f * rg.vel * (0.6 + h) * (near ? 1 : 0.6)) % t.grid.rows; - const x = Math.floor(hash(i, 11) * t.grid.cols) - C + Math.round(Math.sin(f * 0.03 + i) * rg.sway); - const ground = R * 0.45 + Math.sin(x * 0.05 + 1) * 3 + Math.sin(x * 0.13) * 2; - const y = Math.floor(rg.rise ? ground - travel : Math.min(travel - R, ground)); - put(x, y, near ? rg.glyph : '.', rgb); - } - }); -} - -function rebuild() { - t.layers.clear(); - mode++; - weatherLayer(false); - weatherLayer(true); - t.layers.add().draw(drawHud); -} - -t.setup(() => rebuild()); - -t.draw(() => { - t.background(4, 8, 12); - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - - for (let x = -C; x < C; x++) { - const ridge = R * 0.45 + Math.sin(x * 0.05 + 1) * 3 + Math.sin(x * 0.13) * 2; - for (let y = -R; y < R; y++) { - const h = hash(x, y); - if (h > 0.986 && y < ridge) put(x, y, h > 0.994 ? '+' : '.', [70, 90, 110]); - if (y > ridge) put(x, y, y - ridge > 4 ? '#' : ':', [16, 34, 30]); - } - } - - if (t.frameCount % 240 === 0) rebuild(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md index 26411fc1..7c2cc25b 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md @@ -34,100 +34,5 @@ Move a user-created layer to a new index in the stack. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} - -const layer1 = t.layers.add(); -const layer2 = t.layers.add({ blendMode: 'screen', opacity: 0.55 }); -const layer3 = t.layers.add({ blendMode: 'additive', opacity: 0.4 }); -const labelLayer = t.layers.add(); - -layer1.draw(() => { - t.clear(); - - for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { - for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { - const v = Math.sin(x * 0.12 + t.frameCount * 0.02) * Math.cos(y * 0.14 + t.frameCount * 0.014); - if (Math.abs(v) < 0.12) continue; - - t.push(); - t.translate(x, y); - t.charColor(180 + v * 75, 80 + v * 80, 20 + v * 40); - t.char(v > 0.5 ? '@' : v > 0.25 ? '+' : '.'); - t.point(); - t.pop(); - } - } -}); - -layer2.draw(() => { - t.clear(); - - for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { - for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { - const v = Math.sin((x + y) * 0.11 + t.frameCount * 0.022) * Math.sin((x - y) * 0.11 + t.frameCount * 0.016); - if (Math.abs(v) < 0.1) continue; - - t.push(); - t.translate(x, y); - t.charColor(40 + v * 60, 160 + v * 95, 120 + v * 55); - t.char(v > 0.5 ? '@' : v > 0.25 ? '+' : '.'); - t.point(); - t.pop(); - } - } -}); - -layer3.draw(() => { - t.clear(); - - for (let y = -(t.grid.rows >> 1); y <= t.grid.rows >> 1; y++) { - for (let x = -(t.grid.cols >> 1); x <= t.grid.cols >> 1; x++) { - const d = Math.sqrt(x * x * 0.9 + y * y) * 0.16; - const v = Math.sin(d - t.frameCount * 0.025) / (d * 0.2 + 1); - if (v < 0.08) continue; - - t.push(); - t.translate(x, y); - t.charColor(120 + v * 100, 50 + v * 60, 200 + v * 55); - t.char(v > 0.4 ? '@' : v > 0.2 ? '+' : '.'); - t.point(); - t.pop(); - } - } -}); - -t.draw(() => { - t.background(6, 10, 22); - if (t.frameCount % 75 === 0 && t.layers.all.length > 2) t.layers.move(t.layers.all[0], t.layers.all.length - 2); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2), - top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - - drawText('LAYERMANAGER.MOVE', left + 3, y++, [100, 255, 140]); - drawText('CONCEPT: MOVE LAYER INDEX', left + 3, y++, [100, 220, 255]); - drawText('nrml / screen 0.55 / add 0.4', left + 3, y++, [140, 190, 255]); - drawText('Bottom layer rotates to the top.', left + 3, y++, [140, 160, 190]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md index 453f3f6c..b7c86788 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md @@ -33,100 +33,5 @@ Remove and dispose a user-created layer. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const SPAWNS = [ - [-16, -5], - [12, -8], - [3, 5], - [-7, 9], - [17, 3], -]; -const rings = []; -const labelLayer = t.layers.add(); -let spawns = 0; - -function drawText(text, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(text, x, y); - t.pop(); -} -function put(x, y, glyph, rgb) { - t.push(); - t.translate(x, y); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.char(glyph); - t.point(); - t.pop(); -} - -function spawnRing() { - const [cx, cy] = SPAWNS[spawns++ % SPAWNS.length]; - const layer = t.layers.add({ blendMode: t.BLEND_ADDITIVE }); - const born = t.frameCount; - - layer.draw(() => { - t.clear(); - const age = t.frameCount - born; - const r = 1 + age * 0.16; - - for (let a = 0; a < Math.PI * 2; a += 0.09) { - const ca = Math.cos(a), - sa = Math.sin(a); - put(cx + Math.round(ca * r * 2.1), cy + Math.round(sa * r), '.', [120, 220, 255]); - if (age > 20) put(cx + Math.round(ca * r * 1.15), cy + Math.round(sa * r * 0.55), '.', [70, 140, 190]); - } - }); - - rings.push({ layer, born }); - t.layers.move(labelLayer, Number.MAX_SAFE_INTEGER); -} - -t.draw(() => { - t.background(3, 7, 18); - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - - for (let x = -C; x < C; x += 3) - for (let y = -R; y < R; y += 2) put(x, y, '.', [10, 18 + (y / R) * 14, 34 + (y / R) * 22]); - - if (t.frameCount % 34 === 0) spawnRing(); - - for (let i = rings.length - 1; i >= 0; i--) { - const age = t.frameCount - rings[i].born; - rings[i].layer.opacity(Math.max(0, 1 - age / 90)); - - if (age > 90) { - t.layers.remove(rings[i].layer); - rings.splice(i, 1); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('LAYERMANAGER.REMOVE', x, y++, [100, 255, 140]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText('CONCEPT: DISPOSE LAYERS', x, y++, [100, 220, 255]); - drawText('Dead ripples are removed.', x, y++, [140, 160, 190]); - drawText('------------------------------------', x, y++, [80, 100, 150]); - drawText(`ACTIVE RINGS: ${rings.length}`, x, y++, [140, 255, 180]); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md index d0818598..ac017c46 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md @@ -34,102 +34,5 @@ Swap two user-created layers. ## Example -```javascript -const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 }); - -const RAMP = ' .:-=+*#%@'; -const warm = t.layers.add({ blendMode: 'normal' }); -const cool = t.layers.add({ blendMode: 'normal' }); -const label = t.layers.add(); - -function text(value, x, y, rgb = [255, 255, 255]) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(rgb[0], rgb[1], rgb[2]); - t.print(value, x, y); - t.pop(); -} -function put(x, y, glyph, fg, bg) { - t.push(); - t.translate(x, y); - t.charColor(fg[0], fg[1], fg[2]); - if (bg) t.cellColor(bg[0], bg[1], bg[2]); - t.char(glyph); - t.point(); - t.pop(); -} -function paint(fn, threshold, fgBase, bgBase) { - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - for (let y = -R; y <= R; y++) - for (let x = -C; x <= C; x++) { - const v = fn(x, y); - if (v < threshold) continue; - const idx = Math.min(RAMP.length - 1, Math.floor(v * (RAMP.length + 1))); - put( - x, - y, - RAMP[idx], - [Math.floor(fgBase[0] * v), Math.floor(fgBase[1] * v), Math.floor(fgBase[2] * v)], - [Math.floor(bgBase[0] * v), Math.floor(bgBase[1] * v), Math.floor(bgBase[2] * v)] - ); - } -} - -warm.draw(() => { - t.clear(); - const f = t.frameCount * 0.012; - paint( - (x, y) => - 1 - Math.abs((((x + y + Math.sin(x * 0.07 + f) * 4 + Math.cos(y * 0.06 + f * 0.7) * 4) * 0.16) % 2) - 1), - 0.36, - [235, 130, 35], - [35, 12, 4] - ); -}); - -cool.draw(() => { - t.clear(); - const f = t.frameCount * 0.011; - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - paint( - (x, y) => { - let best = 0; - for (let i = 0; i < 7; i++) { - const sx = Math.sin(i * 1.9 + f * 0.6) * C * 0.5; - const sy = Math.cos(i * 1.5 + f * 0.45) * R * 0.5; - best = Math.max(best, Math.exp(-Math.hypot(x - sx, y - sy) * 0.16)); - } - return best; - }, - 0.38, - [60, 175, 240], - [4, 24, 42] - ); -}); - -t.draw(() => { - t.background(4, 7, 18); - const C = Math.floor(t.grid.cols / 2), - R = Math.floor(t.grid.rows / 2); - for (let x = -C; x <= C; x += 4) - for (let y = -R; y <= R; y += 3) if ((x * 7 + y * 13) % 19 === 0) put(x, y, '.', [16, 24, 45]); - if (t.frameCount % 120 === 0) t.layers.swap(warm, cool); -}); - -label.draw(() => { - t.clear(); - const L = -Math.floor(t.grid.cols / 2), - T = -Math.floor(t.grid.rows / 2); - let y = T + 3; - const warmTop = Math.floor(t.frameCount / 120) % 2 === 0; - text('LAYERMANAGER.SWAP', L + 3, y++, [100, 255, 140]); - text('------------------------------------', L + 3, y++, [80, 100, 150]); - text('Normal blend: top occludes below.', L + 3, y++, [100, 220, 255]); - text(warmTop ? 'TOP: WARM FIELD' : 'TOP: COOL ORBS', L + 3, y++, [140, 255, 180]); -}); - -t.windowResized(() => t.resizeCanvas(window.innerWidth, window.innerHeight)); -``` + diff --git a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md index a778101a..a9e3c54c 100644 --- a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md +++ b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md @@ -42,82 +42,7 @@ that should get brighter as animated layers overlap. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_ADDITIVE; -const modeName = 'BLEND_ADDITIVE'; -const accent = [255, 100, 80]; -const base = [28, 80, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.78 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(4, 8, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.17 + y * 0.11 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : ':'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(2, 6, 16); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 16; i++) { - const angle = i * 22.5 + ring * 11 + t.frameCount * 1.6; - const radius = 4 + ring * 3.8 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '*' : '@'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 10, 12); - t.rect(3, 2 + (i % 2)); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_ADDITIVE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ADDITIVE LIGHT', x, y++, 100, 220, 255); - drawText('Overlaps grow brighter.', x, y++, 140, 160, 190); - drawText('Good for sparks and glow.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -134,82 +59,7 @@ shapes that should compress color toward black. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_COLOR_BURN; -const modeName = 'BLEND_COLOR_BURN'; -const accent = [120, 50, 70]; -const base = [220, 170, 110]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.034; - t.background(50, 34, 22); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.13 - y * 0.15 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '%' : '+'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(52, 28, 16); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 18 - t.frameCount * 1.2; - const radius = 5 + ring * 3.8 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '#' : 'X'); - t.charColor(...accent); - t.cellColor(24 + ring * 10, 5, 10 + ring * 6); - t.rect(4, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_COLOR_BURN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: BURN SHADOWS', x, y++, 100, 220, 255); - drawText('Color compresses darker.', x, y++, 140, 160, 190); - drawText('Motion leaves dense marks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -226,82 +76,7 @@ should push quickly toward white. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_COLOR_DODGE; -const modeName = 'BLEND_COLOR_DODGE'; -const accent = [255, 245, 170]; -const base = [42, 80, 130]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.72 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.038; - t.background(4, 10, 24); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.15 + y * 0.14 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(3, 8, 20); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 19 + t.frameCount * 1.8; - const radius = 4 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '*' : '@'); - t.charColor(...accent); - t.cellColor(45 + ring * 22, 42 + ring * 16, 16); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_COLOR_DODGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DODGE FLARES', x, y++, 100, 220, 255); - drawText('Small marks bloom fast.', x, y++, 140, 160, 190); - drawText('Highlights push to white.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -318,82 +93,7 @@ existing composition. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_DARKEN; -const modeName = 'BLEND_DARKEN'; -const accent = [90, 110, 170]; -const base = [220, 190, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.03; - t.background(46, 40, 25); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.16 - y * 0.1 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(48, 38, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 19 + t.frameCount; - const radius = 5 + ring * 3.8 + Math.cos(time + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time * 1.5 + i) * 2); - t.char(ring % 2 ? '%' : '#'); - t.charColor(...accent); - t.cellColor(10 + ring * 7, 12 + ring * 8, 30 + ring * 14); - t.rect(4, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_DARKEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: DARKER CHANNELS', x, y++, 100, 220, 255); - drawText('Only darker color wins.', x, y++, 140, 160, 190); - drawText('Moving marks add shade.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -410,82 +110,7 @@ overlaps that reveal contrast where colors diverge. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_DIFFERENCE; -const modeName = 'BLEND_DIFFERENCE'; -const accent = [255, 255, 255]; -const base = [70, 180, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.9 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.036; - t.background(8, 16, 24); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.17 + y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '-'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(4, 12, 20); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 29 + t.frameCount * 1.5; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '@' : '#'); - t.charColor(...accent); - t.cellColor(70, 70, 70); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_DIFFERENCE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT BY DISTANCE', x, y++, 100, 220, 255); - drawText('Unlike colors spark edges.', x, y++, 140, 160, 190); - drawText('Overlaps flip the field.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -502,82 +127,7 @@ overlays that should shift color without the full edge of difference. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_EXCLUSION; -const modeName = 'BLEND_EXCLUSION'; -const accent = [230, 230, 255]; -const base = [120, 100, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.88 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.033; - t.background(16, 14, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.16 - y * 0.13 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 32, base[2]); - t.cellColor(10, 8, 24); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 25 - t.frameCount * 1.25; - const radius = 5 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(45 + ring * 12, 45 + ring * 12, 68); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_EXCLUSION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOFT INVERSION', x, y++, 100, 220, 255); - drawText('Difference with less bite.', x, y++, 140, 160, 190); - drawText('Color shifts stay muted.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -594,82 +144,7 @@ marks that should strongly reshape contrast. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_HARD_LIGHT; -const modeName = 'BLEND_HARD_LIGHT'; -const accent = [255, 220, 70]; -const base = [65, 75, 150]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.04; - t.background(10, 12, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.18 - y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '#' : ':'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(8, 8, 24); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 27 - t.frameCount * 1.6; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2.4; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? 'X' : '#'); - t.charColor(...accent); - t.cellColor(45 + ring * 20, 38 + ring * 12, 6); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_HARD_LIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: HARD CONTRAST', x, y++, 100, 220, 255); - drawText('The top layer drives punch.', x, y++, 140, 160, 190); - drawText('Edges become more graphic.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -686,82 +161,7 @@ existing composition. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_LIGHTEN; -const modeName = 'BLEND_LIGHTEN'; -const accent = [255, 230, 130]; -const base = [40, 70, 105]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.034; - t.background(8, 15, 28); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.13 + y * 0.18 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? ':' : '.'); - t.charColor(base[0], base[1] + wave * 25, base[2]); - t.cellColor(5, 10, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 13 - t.frameCount * 1.1; - const radius = 4 + ring * 4 + Math.sin(time + i) * 2.2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time * 1.6 + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(45 + ring * 15, 42 + ring * 10, 18); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_LIGHTEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LIGHTER CHANNELS', x, y++, 100, 220, 255); - drawText('Only brighter color wins.', x, y++, 140, 160, 190); - drawText('Moving marks reveal light.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -778,82 +178,7 @@ shadow-like patterns that preserve underlying contrast. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_MULTIPLY; -const modeName = 'BLEND_MULTIPLY'; -const accent = [130, 180, 255]; -const base = [220, 150, 90]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.84 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.032; - t.background(42, 30, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.12 - y * 0.16 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '%' : '+'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(50, 28, 12); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 20; i++) { - const angle = i * 18 + ring * 14 - t.frameCount * 1.1; - const radius = 6 + ring * 4 + Math.cos(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + ring) * 2); - t.char(ring % 2 ? 'X' : '#'); - t.charColor(...accent); - t.cellColor(12, 25 + ring * 20, 58 + ring * 12); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_MULTIPLY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: MULTIPLY SHADE', x, y++, 100, 220, 255); - drawText('Overlap darkens the base.', x, y++, 140, 160, 190); - drawText('Color stays tied to below.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -870,83 +195,7 @@ controlling how much of the layer covers the layers below it. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_NORMAL; -const modeName = 'BLEND_NORMAL'; -const accent = [250, 180, 90]; -const base = [35, 70, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.82 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.035; - t.background(8, 10, 22); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.18 + y * 0.13 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '+' : '.'); - t.charColor(base[0] + wave * 30, base[1] + 20, base[2]); - t.cellColor(4, 8, 18); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 17 + t.frameCount * (1.2 + ring * 0.2); - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.rotateZ(-angle * 0.5); - t.char(ring % 2 ? '@' : '#'); - t.charColor(...accent); - t.cellColor(20 + ring * 18, 16, 32 + ring * 12); - t.rect(3 + (i % 2), 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_NORMAL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: NORMAL BLEND', x, y++, 100, 220, 255); - drawText('Animated layer covers below.', x, y++, 140, 160, 190); - drawText('Opacity controls the mix.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -963,82 +212,7 @@ highlights in one pass. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_OVERLAY; -const modeName = 'BLEND_OVERLAY'; -const accent = [255, 90, 190]; -const base = [80, 125, 190]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.83 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.037; - t.background(10, 18, 32); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.14 + y * 0.12 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : '-'); - t.charColor(base[0], base[1] + wave * 35, base[2]); - t.cellColor(8, 14, 26); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 21 + t.frameCount * 1.35; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.sin(time + i) * 2); - t.char(ring % 2 ? '@' : '%'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 10, 42 + ring * 12); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_OVERLAY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CONTRAST BOOST', x, y++, 100, 220, 255); - drawText('Dark stays deep, light lifts.', x, y++, 140, 160, 190); - drawText('Good for graphic masks.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -1055,82 +229,7 @@ areas while preserving highlight detail. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SCREEN; -const modeName = 'BLEND_SCREEN'; -const accent = [100, 220, 255]; -const base = [85, 45, 120]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.8 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.036; - t.background(12, 8, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.2 + y * 0.08 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(8, 4, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 23 + t.frameCount * 1.3; - const radius = 6 + ring * 3.5 + Math.sin(time + i) * 2; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time * 1.4 + i) * 2); - t.char(ring % 2 ? '*' : '+'); - t.charColor(...accent); - t.cellColor(5, 30 + ring * 10, 45 + ring * 20); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SCREEN', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SCREEN LIGHT', x, y++, 100, 220, 255); - drawText('Dark areas lift upward.', x, y++, 140, 160, 190); - drawText('Highlights stay open.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -1147,82 +246,7 @@ animated texture that should stay subtle. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SOFT_LIGHT; -const modeName = 'BLEND_SOFT_LIGHT'; -const accent = [255, 170, 150]; -const base = [70, 120, 160]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.029; - t.background(12, 20, 30); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.12 + y * 0.15 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '~' : '.'); - t.charColor(base[0], base[1] + wave * 28, base[2]); - t.cellColor(8, 14, 22); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 5; ring++) { - for (let i = 0; i < 14; i++) { - const angle = i * 25.7 + ring * 16 + t.frameCount * 0.9; - const radius = 5 + ring * 3.5 + Math.sin(time + i) * 1.5; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '+' : '*'); - t.charColor(...accent); - t.cellColor(28 + ring * 14, 20 + ring * 10, 30); - t.rect(3, 3); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SOFT_LIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOFT CONTRAST', x, y++, 100, 220, 255); - drawText('Texture changes gently.', x, y++, 140, 160, 190); - drawText('Useful for atmosphere.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + *** @@ -1239,79 +263,4 @@ that remove brightness from the composite. #### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const mode = t.BLEND_SUBTRACT; -const modeName = 'BLEND_SUBTRACT'; -const accent = [180, 230, 255]; -const base = [210, 120, 70]; -const blendLayer = t.layers.add({ blendMode: mode, opacity: 0.86 }); -const labelLayer = t.layers.add(); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - const time = t.frameCount * 0.033; - t.background(48, 28, 18); - const { cols, rows } = t.grid; - for (let y = -Math.floor(rows / 2); y < rows / 2; y += 3) { - for (let x = -Math.floor(cols / 2); x < cols / 2; x += 3) { - const wave = Math.sin(x * 0.11 + y * 0.19 + time); - t.push(); - t.translate(x, y); - t.char(wave > 0 ? '=' : '+'); - t.charColor(base[0], base[1] + wave * 30, base[2]); - t.cellColor(55, 24, 10); - t.rect(2, 2); - t.pop(); - } - } - blendLayer.draw(() => { - t.clear(); - for (let ring = 0; ring < 4; ring++) { - for (let i = 0; i < 18; i++) { - const angle = i * 20 + ring * 15 - t.frameCount * 1.4; - const radius = 5 + ring * 4 + Math.sin(time * 2 + i) * 1.8; - t.push(); - t.rotateZ(angle); - t.translate(radius, Math.cos(time + i) * 2); - t.char(ring % 2 ? '/' : '\\'); - t.charColor(...accent); - t.cellColor(35 + ring * 18, 45 + ring * 12, 58); - t.rect(4, 2); - t.pop(); - } - } - }); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - drawText('TEXTMODIFIER.BLEND_SUBTRACT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUBTRACT CUTS', x, y++, 100, 220, 255); - drawText('The top layer removes light.', x, y++, 140, 160, 190); - drawText('Bright marks carve paths.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`MODE: ${modeName}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/layering/index.md b/api/textmode.js/namespaces/layering/index.md index 6deb222b..d00c0784 100644 --- a/api/textmode.js/namespaces/layering/index.md +++ b/api/textmode.js/namespaces/layering/index.md @@ -33,9 +33,3 @@ All modules and types related to multi-layered textmode rendering. | Interface | Description | | ------ | ------ | | [TextmodeLayerOptions](interfaces/TextmodeLayerOptions.md) | Options for layers created with [TextmodeLayerManager.add](classes/TextmodeLayerManager/methods/add.md). | - -## Variables - -| Variable | Description | -| ------ | ------ | -| [~~TEXTMODE\_LAYER\_BLEND\_MODES~~](variables/TEXTMODE_LAYER_BLEND_MODES.md) | Use the [LayerBlendMode](enumerations/LayerBlendMode.md) enum and the `t.BLEND_*` constants (e.g. `t.BLEND_ADDITIVE`). String blend modes are accepted for backwards compatibility and emit a deprecation warning; they will be removed in a future version. | diff --git a/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md b/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md index 65faf1ac..df7f64b1 100644 --- a/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md +++ b/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md @@ -22,7 +22,7 @@ Options for layers created with [TextmodeLayerManager.add](../classes/TextmodeLa | Property | Type | Description | | ------ | ------ | ------ | -| `blendMode?` | \| `"normal"` \| `"subtract"` \| `"darken"` \| `"difference"` \| `"exclusion"` \| `"lighten"` \| `"multiply"` \| `"overlay"` \| `"screen"` \| `"additive"` \| `"softLight"` \| `"hardLight"` \| `"colorDodge"` \| `"colorBurn"` \| [`LayerBlendMode`](../enumerations/LayerBlendMode.md) | Blend mode used when compositing this layer. Defaults to `LayerBlendMode.NORMAL`. Pass a [LayerBlendMode](../enumerations/LayerBlendMode.md) constant (e.g. `t.BLEND_ADDITIVE`) or a legacy string (e.g. `'additive'` — deprecated, emits a warning). | +| `blendMode?` | [`LayerBlendMode`](../enumerations/LayerBlendMode.md) | Blend mode used when compositing this layer. Defaults to `LayerBlendMode.NORMAL`. Pass a [LayerBlendMode](../enumerations/LayerBlendMode.md) constant such as `t.BLEND_ADDITIVE`. | | `fontSize?` | `number` | Font size for the layer's glyph source. Defaults to `16`. | | `fontSource?` | `string` \| [`TextmodeFont`](../../fonts/classes/TextmodeFont.md) | Source for the font to use in this layer. Can be a URL/path to a font file, or an existing TextmodeFont instance. Existing TextmodeFont inputs are forked per layer to keep resources independent. | | `offsetX?` | `number` | Horizontal layer offset in pixels. Defaults to `0`. | diff --git a/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md b/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md deleted file mode 100644 index 6cfcb128..00000000 --- a/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -layout: doc -editLink: true -deprecated: 0 -title: TEXTMODE_LAYER_BLEND_MODES -description: Use the LayerBlendMode enum and the t.BLEND_* constants (e.g. t.BLEND_ADDITIVE). String blend modes are accepted for backwards compatibility and emit a depre... -category: Variables -api: true -namespace: layering -kind: Variable -lastModified: 2026-07-31 ---- - -[textmode.js](../../../index.md) / [layering](../index.md) / TEXTMODE\_LAYER\_BLEND\_MODES - -# Variable: TEXTMODE\_LAYER\_BLEND\_MODES - -```ts -const TEXTMODE_LAYER_BLEND_MODES: readonly ["normal", "additive", "multiply", "screen", "subtract", "darken", "lighten", "overlay", "softLight", "hardLight", "colorDodge", "colorBurn", "difference", "exclusion"]; -``` - -Use the [LayerBlendMode](../enumerations/LayerBlendMode.md) enum and the `t.BLEND_*` constants -(e.g. `t.BLEND_ADDITIVE`). String blend modes are accepted for backwards -compatibility and emit a deprecation warning; they will be removed in a -future version. - -## See - - - [LayerBlendMode](../enumerations/LayerBlendMode.md) - - [layering.TEXTMODE\_LAYER\_BLEND\_MODES API reference](https://code.textmode.art/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES) diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage.md b/api/textmode.js/namespaces/media/classes/TextmodeImage.md index aece6168..0e9a0441 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage.md @@ -22,87 +22,7 @@ and configure conversion through inherited chainable methods. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let image = null; - -function createReactionCanvas() { - const canvas = document.createElement('canvas'); - canvas.width = 64; - canvas.height = 48; - const ctx = canvas.getContext('2d'); - - const imgData = ctx.createImageData(64, 48); - const data = imgData.data; - - for (let y = 0; y < 48; y++) { - for (let x = 0; x < 64; x++) { - const idx = (y * 64 + x) * 4; - const v = Math.sin(x * 0.15) * Math.cos(y * 0.15) + Math.sin(x * 0.3 + y * 0.2); - const norm = (v + 2) / 4; - - data[idx] = Math.floor(15 + norm * 240); - data[idx + 1] = Math.floor(23 + norm * 160); - data[idx + 2] = Math.floor(42 + norm * 210); - data[idx + 3] = 255; - } - } - ctx.putImageData(imgData, 0, 0); - return canvas.toDataURL(); -} - -t.setup(async () => { - image = await t.loadImage(createReactionCanvas()); - image.characters(' .:-=+*#%@'); - image.cellColorMode('sampled'); -}); - -t.draw(() => { - t.background(15, 23, 42); - if (!image) return; - - t.push(); - t.rotateZ(Math.sin(t.frameCount * 0.03) * 64); - t.image(image, Math.floor(t.grid.cols * 0.6), Math.floor(t.grid.rows * 0.6)); - t.pop(); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('TEXTMODEIMAGE.CREATION', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: REACTION CANV CONVERTER', x, y++); - t.charColor(140, 160, 190); - t.print('Loads HTML canvas data into image.', x, y++); - t.print('Converts source pixels into cells.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(245, 158, 11); - t.print(`IMAGE SIZE: ${image ? image.width : 0}x${image ? image.height : 0} PX`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Extends diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md index 4161bd8e..54cdfbc2 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md @@ -29,81 +29,7 @@ Ideal draw height in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.height : 0; - drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md index be644b34..cb01d369 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md @@ -29,81 +29,7 @@ Original source height in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.originalHeight : 0; - drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md index 54a3c860..bec7a609 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md @@ -29,81 +29,7 @@ Original source width in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.originalWidth : 0; - drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md index 6787082a..a56d7890 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md @@ -29,81 +29,7 @@ WebGL texture backing this source. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = source && source.texture ? 'READY' : 'WAIT'; - drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md index 624b7bbc..d1c72b5a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md @@ -29,81 +29,7 @@ Ideal draw width in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.width : 0; - drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md index c4764e59..b93ec415 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md @@ -42,97 +42,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let sourceA, sourceB; - -function createTransparentCanvas() { - const canvas = document.createElement('canvas'); - canvas.width = 128; - canvas.height = 128; - const ctx = canvas.getContext('2d'); - if (!ctx) return canvas; - - ctx.clearRect(0, 0, 128, 128); - ctx.lineWidth = 10; - ctx.strokeStyle = '#ffffff'; - ctx.strokeRect(20, 20, 88, 88); - - ctx.fillStyle = '#ffffff'; - ctx.beginPath(); - ctx.arc(64, 64, 30, 0, Math.PI * 2); - ctx.fill(); - - return canvas; -} - -t.setup(() => { - const canvas = createTransparentCanvas(); - - sourceA = t.createTexture(canvas); - sourceA.characters(' .:-=+*#%@'); - - sourceB = t.createTexture(canvas); - sourceB.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (!sourceA || !sourceB) return; - - const time = t.frameCount * 0.05; - const pulse = 0.5 + 0.5 * Math.sin(time); - sourceB.background(pulse * 255, 100, 255 - pulse * 155); - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); - drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); - drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md index 7690e0a3..efc1e389 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md @@ -36,92 +36,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const ranges = [ - { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, - { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, - { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, -]; - -let rangeSources = []; - -function drawRangeSource(source, x, y, width, height) { - t.push(); - t.translate(x, y); - t.image(source, width, height); - t.pop(); -} - -t.setup(async () => { - rangeSources = await Promise.all( - ranges.map(async (range) => { - const source = await t.loadImage(IMAGE_URL); - source.brightnessRange(range.start, range.end); - source.characters(range.characters); - source.charColorMode('fixed'); - source.charColor(range.charColor); - source.cellColorMode('fixed'); - source.cellColor('#00000000'); - return source; - }) - ); -}); - -t.draw(() => { - t.background(4, 7, 18); - if (rangeSources.length === 0) return; - - const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); - const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); - const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); - const totalWidth = panelWidth * 3 + gap * 2; - const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); - const y = -1; - - for (let i = 0; i < rangeSources.length; i++) { - const x = startX + i * (panelWidth + gap); - drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); - drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); - drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); - drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md index fe5849d5..0471d8aa 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md @@ -42,71 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let red = 40; -let blue = 80; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed').charColor(255); - techSource.cellColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - red = Math.round(40 + 40 * Math.sin(time)); - blue = Math.round(80 + 40 * Math.cos(time * 0.7)); - - techSource.cellColor(red, 40, blue); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md index 003d6d26..2eb2ccb0 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.cellColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.cellColorMode('fixed').cellColor(20, 30, 60); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md index c7049197..f4b2f769 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md @@ -42,70 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let r = 150; -let g = 150; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - r = Math.round(150 + 105 * Math.sin(time)); - g = Math.round(150 + 105 * Math.cos(time * 0.7)); - - techSource.charColor(r, g, 100); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md index e053d0e8..c5ac1727 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.charColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.charColorMode('fixed').charColor(140, 255, 180); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md index c9e77697..61fe787d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let pointerSource = null; - -t.setup(async () => { - pointerSource = await t.loadImage(IMAGE_URL); - pointerSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!pointerSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - pointerSource.charRotation(0); - t.image(pointerSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - pointerSource.charRotation(90); - t.image(pointerSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); - drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md index 7b415ba9..fab2da67 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md @@ -35,82 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.characters(' .oO@'); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const chars = ' .oO@'; - drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md index 1335ff12..b3e62ab4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md @@ -31,82 +31,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); - source.clearConversions(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STACK: CLEARED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md index 5b2d5e5f..de1edc0c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md @@ -35,59 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let source = null; - -t.setup(async () => { - source = await t.loadImage(IMAGE_URL); - source.conversionMode('brightness'); - source.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(4, 7, 18); - t.background(0); - if (!source) return; - - t.image(source, source.width, source.height); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md index a82eeaaa..928bb553 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md @@ -35,101 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - Object.assign(canvas, { width: 128, height: 80 }); - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 128, 80); - gradient.addColorStop(0, '#020617'); - gradient.addColorStop(0.45, '#0ea5e9'); - gradient.addColorStop(1, '#f8fafc'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 128, 80); - ctx.fillStyle = '#f97316'; - ctx.fillRect(15, 16, 34, 44); - ctx.fillStyle = '#fde68a'; - ctx.fillRect(78, 22, 34, 34); - return canvas.toDataURL(); -} - -function configureSource(source) { - source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); -} - -function brightnessPass(start, end, characters, charColor) { - return { - mode: 'brightness', - brightnessStart: start, - brightnessEnd: end, - characters, - charColorMode: 'fixed', - charColor, - }; -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([ - brightnessPass(0, 84, ' .:', '#38bdf8'), - brightnessPass(85, 169, '-=+', '#facc15'), - brightnessPass(170, 255, '*#@', '#f8fafc'), - ]); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - if (!source) return; - - const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); - const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); - const y = Math.floor(t.grid.rows * 0.12); - t.push(); - t.translate(0, y); - t.image(source, width, height); - t.pop(); - drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); - drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('PASSES: 3', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md index 98093d75..8583dccb 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md @@ -27,89 +27,7 @@ Dispose of the resource and free associated WebGL textures. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.mouseClicked(() => { - if (source && !disposed) { - source.dispose(); - disposed = true; - } -}); - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = disposed ? 'Disposed' : 'Active'; - drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md index b0fd43b2..3a0a8391 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipX(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipX(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); - drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md index fb9a036c..e94aca69 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipY(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipY(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); - drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md index ce4a12ec..4edeb65f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let gradientSource = null; - -t.setup(async () => { - gradientSource = await t.loadImage(IMAGE_URL); - gradientSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!gradientSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - gradientSource.invert(false); - t.image(gradientSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - gradientSource.invert(true); - t.image(gradientSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); - drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md index d0595354..c4cd5613 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md @@ -29,78 +29,5 @@ Ideal draw height in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.height : 0; - drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md index aa6b2559..8eef9b22 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md @@ -29,78 +29,5 @@ Original source height in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.originalHeight : 0; - drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md index 435059eb..8c964474 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md @@ -29,78 +29,5 @@ Original source width in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.originalWidth : 0; - drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md index 1285feda..a081044c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md @@ -29,78 +29,5 @@ WebGL texture backing this source. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = source && source.texture ? 'READY' : 'WAIT'; - drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md index 7cf7358c..0a18da9d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md @@ -29,78 +29,5 @@ Ideal draw width in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.width : 0; - drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md index fe925dff..ba90d41e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md @@ -42,94 +42,5 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let sourceA, sourceB; - -function createTransparentCanvas() { - const canvas = document.createElement('canvas'); - canvas.width = 128; - canvas.height = 128; - const ctx = canvas.getContext('2d'); - if (!ctx) return canvas; - - ctx.clearRect(0, 0, 128, 128); - ctx.lineWidth = 10; - ctx.strokeStyle = '#ffffff'; - ctx.strokeRect(20, 20, 88, 88); - - ctx.fillStyle = '#ffffff'; - ctx.beginPath(); - ctx.arc(64, 64, 30, 0, Math.PI * 2); - ctx.fill(); - - return canvas; -} - -t.setup(() => { - const canvas = createTransparentCanvas(); - - sourceA = t.createTexture(canvas); - sourceA.characters(' .:-=+*#%@'); - - sourceB = t.createTexture(canvas); - sourceB.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (!sourceA || !sourceB) return; - - const time = t.frameCount * 0.05; - const pulse = 0.5 + 0.5 * Math.sin(time); - sourceB.background(pulse * 255, 100, 255 - pulse * 155); - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); - drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); - drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md index 7288eed9..24f09532 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md @@ -36,89 +36,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const ranges = [ - { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, - { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, - { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, -]; - -let rangeSources = []; - -function drawRangeSource(source, x, y, width, height) { - t.push(); - t.translate(x, y); - t.image(source, width, height); - t.pop(); -} - -t.setup(async () => { - rangeSources = await Promise.all( - ranges.map(async (range) => { - const source = await t.loadImage(IMAGE_URL); - source.brightnessRange(range.start, range.end); - source.characters(range.characters); - source.charColorMode('fixed'); - source.charColor(range.charColor); - source.cellColorMode('fixed'); - source.cellColor('#00000000'); - return source; - }) - ); -}); - -t.draw(() => { - t.background(4, 7, 18); - if (rangeSources.length === 0) return; - - const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); - const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); - const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); - const totalWidth = panelWidth * 3 + gap * 2; - const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); - const y = -1; - - for (let i = 0; i < rangeSources.length; i++) { - const x = startX + i * (panelWidth + gap); - drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); - drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); - drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); - drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md index ba04be89..6a83b248 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md @@ -42,68 +42,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let red = 40; -let blue = 80; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed').charColor(255); - techSource.cellColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - red = Math.round(40 + 40 * Math.sin(time)); - blue = Math.round(80 + 40 * Math.cos(time * 0.7)); - - techSource.cellColor(red, 40, blue); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md index 68b0225a..b5949740 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md @@ -35,72 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.cellColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.cellColorMode('fixed').cellColor(20, 30, 60); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md index 4bc3be73..40de00c8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md @@ -42,67 +42,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let r = 150; -let g = 150; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - r = Math.round(150 + 105 * Math.sin(time)); - g = Math.round(150 + 105 * Math.cos(time * 0.7)); - - techSource.charColor(r, g, 100); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md index b1d455ad..4902d066 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md @@ -35,72 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.charColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.charColorMode('fixed').charColor(140, 255, 180); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md index c73e9d8b..b010857f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md @@ -35,68 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let pointerSource = null; - -t.setup(async () => { - pointerSource = await t.loadImage(IMAGE_URL); - pointerSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!pointerSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - pointerSource.charRotation(0); - t.image(pointerSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - pointerSource.charRotation(90); - t.image(pointerSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); - drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md index 0a4e222d..bbe45d53 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md @@ -35,79 +35,5 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.characters(' .oO@'); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const chars = ' .oO@'; - drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md index d1728d1d..ea702ffa 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md @@ -31,79 +31,5 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); - source.clearConversions(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STACK: CLEARED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md index d3326228..fd7235ae 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md @@ -35,56 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let source = null; - -t.setup(async () => { - source = await t.loadImage(IMAGE_URL); - source.conversionMode('brightness'); - source.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(4, 7, 18); - t.background(0); - if (!source) return; - - t.image(source, source.width, source.height); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md index 4e97ac69..bc39b77b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md @@ -35,98 +35,5 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - Object.assign(canvas, { width: 128, height: 80 }); - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 128, 80); - gradient.addColorStop(0, '#020617'); - gradient.addColorStop(0.45, '#0ea5e9'); - gradient.addColorStop(1, '#f8fafc'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 128, 80); - ctx.fillStyle = '#f97316'; - ctx.fillRect(15, 16, 34, 44); - ctx.fillStyle = '#fde68a'; - ctx.fillRect(78, 22, 34, 34); - return canvas.toDataURL(); -} - -function configureSource(source) { - source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); -} - -function brightnessPass(start, end, characters, charColor) { - return { - mode: 'brightness', - brightnessStart: start, - brightnessEnd: end, - characters, - charColorMode: 'fixed', - charColor, - }; -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([ - brightnessPass(0, 84, ' .:', '#38bdf8'), - brightnessPass(85, 169, '-=+', '#facc15'), - brightnessPass(170, 255, '*#@', '#f8fafc'), - ]); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - if (!source) return; - - const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); - const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); - const y = Math.floor(t.grid.rows * 0.12); - t.push(); - t.translate(0, y); - t.image(source, width, height); - t.pop(); - drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); - drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('PASSES: 3', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md index e667fb5b..cf7c4c0b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md @@ -27,89 +27,7 @@ Dispose of the resource and free associated WebGL textures. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.mouseClicked(() => { - if (source && !disposed) { - source.dispose(); - disposed = true; - } -}); - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = disposed ? 'Disposed' : 'Active'; - drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Overrides diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md index 21a73f30..8239d1e3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md @@ -35,72 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipX(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipX(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); - drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md index 469a9af1..be33323e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md @@ -35,72 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipY(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipY(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); - drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md index ce6590f4..206a3e4f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md @@ -35,68 +35,5 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let gradientSource = null; - -t.setup(async () => { - gradientSource = await t.loadImage(IMAGE_URL); - gradientSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!gradientSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - gradientSource.invert(false); - t.image(gradientSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - gradientSource.invert(true); - t.image(gradientSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); - drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md index 37704f58..90503f49 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md @@ -29,81 +29,7 @@ Ideal draw height in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.height : 0; - drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md index f709d41d..1cb74f19 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md @@ -29,81 +29,7 @@ Original source height in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.originalHeight : 0; - drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md index 3f89570c..26cc46d5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md @@ -29,81 +29,7 @@ Original source width in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.originalWidth : 0; - drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md index 2fbf2f07..f841980e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md @@ -29,65 +29,5 @@ Source element this texture captures. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let texture = null; -let sourceCanvas = null; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - sourceCanvas = document.createElement('canvas'); - sourceCanvas.width = 120; - sourceCanvas.height = 80; - texture = t.createTexture(sourceCanvas); - texture.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(8, 10, 18); - if (!texture) return; - const ctx = sourceCanvas.getContext('2d'); - ctx.fillStyle = '#0a0d1a'; - ctx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); - ctx.fillStyle = '#38bdf8'; - ctx.beginPath(); - ctx.arc(60 + Math.sin(t.frameCount * 0.05) * 30, 40, 18, 0, Math.PI * 2); - ctx.fill(); - t.image(texture, Math.floor(t.grid.cols * 0.5), Math.floor(t.grid.rows * 0.5)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODETEXTURE.SOURCE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: BACKING ELEMENT', x, y++, 100, 220, 255); - drawText('Texture keeps its source.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const size = sourceCanvas ? sourceCanvas.width + 'x' + sourceCanvas.height : '0x0'; - drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md index 0f5f77aa..8b9abf25 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md @@ -29,81 +29,7 @@ WebGL texture backing this source. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = source && source.texture ? 'READY' : 'WAIT'; - drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md index 33087f15..8a3b37b4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md @@ -29,81 +29,7 @@ Ideal draw width in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.width : 0; - drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md index cdc5df2b..3e6e99ba 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md @@ -42,97 +42,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let sourceA, sourceB; - -function createTransparentCanvas() { - const canvas = document.createElement('canvas'); - canvas.width = 128; - canvas.height = 128; - const ctx = canvas.getContext('2d'); - if (!ctx) return canvas; - - ctx.clearRect(0, 0, 128, 128); - ctx.lineWidth = 10; - ctx.strokeStyle = '#ffffff'; - ctx.strokeRect(20, 20, 88, 88); - - ctx.fillStyle = '#ffffff'; - ctx.beginPath(); - ctx.arc(64, 64, 30, 0, Math.PI * 2); - ctx.fill(); - - return canvas; -} - -t.setup(() => { - const canvas = createTransparentCanvas(); - - sourceA = t.createTexture(canvas); - sourceA.characters(' .:-=+*#%@'); - - sourceB = t.createTexture(canvas); - sourceB.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (!sourceA || !sourceB) return; - - const time = t.frameCount * 0.05; - const pulse = 0.5 + 0.5 * Math.sin(time); - sourceB.background(pulse * 255, 100, 255 - pulse * 155); - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); - drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); - drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md index 236508b4..d712254c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md @@ -36,92 +36,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const ranges = [ - { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, - { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, - { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, -]; - -let rangeSources = []; - -function drawRangeSource(source, x, y, width, height) { - t.push(); - t.translate(x, y); - t.image(source, width, height); - t.pop(); -} - -t.setup(async () => { - rangeSources = await Promise.all( - ranges.map(async (range) => { - const source = await t.loadImage(IMAGE_URL); - source.brightnessRange(range.start, range.end); - source.characters(range.characters); - source.charColorMode('fixed'); - source.charColor(range.charColor); - source.cellColorMode('fixed'); - source.cellColor('#00000000'); - return source; - }) - ); -}); - -t.draw(() => { - t.background(4, 7, 18); - if (rangeSources.length === 0) return; - - const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); - const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); - const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); - const totalWidth = panelWidth * 3 + gap * 2; - const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); - const y = -1; - - for (let i = 0; i < rangeSources.length; i++) { - const x = startX + i * (panelWidth + gap); - drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); - drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); - drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); - drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md index 9006a260..e8c561b8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md @@ -42,71 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let red = 40; -let blue = 80; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed').charColor(255); - techSource.cellColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - red = Math.round(40 + 40 * Math.sin(time)); - blue = Math.round(80 + 40 * Math.cos(time * 0.7)); - - techSource.cellColor(red, 40, blue); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md index e78c11da..e1ca7876 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.cellColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.cellColorMode('fixed').cellColor(20, 30, 60); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md index 68f87e72..71b20ee9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md @@ -42,70 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let r = 150; -let g = 150; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - r = Math.round(150 + 105 * Math.sin(time)); - g = Math.round(150 + 105 * Math.cos(time * 0.7)); - - techSource.charColor(r, g, 100); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md index 2baae5d8..31790ac1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.charColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.charColorMode('fixed').charColor(140, 255, 180); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md index cf7c97f3..a6a6024b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let pointerSource = null; - -t.setup(async () => { - pointerSource = await t.loadImage(IMAGE_URL); - pointerSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!pointerSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - pointerSource.charRotation(0); - t.image(pointerSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - pointerSource.charRotation(90); - t.image(pointerSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); - drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md index f30d63b4..ddc50f34 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md @@ -35,82 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.characters(' .oO@'); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const chars = ' .oO@'; - drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md index 00b4ed16..5f1672fe 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md @@ -31,82 +31,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); - source.clearConversions(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STACK: CLEARED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md index a6d085c6..c1653157 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md @@ -35,59 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let source = null; - -t.setup(async () => { - source = await t.loadImage(IMAGE_URL); - source.conversionMode('brightness'); - source.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(4, 7, 18); - t.background(0); - if (!source) return; - - t.image(source, source.width, source.height); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md index 4a8cd840..82f6faf6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md @@ -35,101 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - Object.assign(canvas, { width: 128, height: 80 }); - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 128, 80); - gradient.addColorStop(0, '#020617'); - gradient.addColorStop(0.45, '#0ea5e9'); - gradient.addColorStop(1, '#f8fafc'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 128, 80); - ctx.fillStyle = '#f97316'; - ctx.fillRect(15, 16, 34, 44); - ctx.fillStyle = '#fde68a'; - ctx.fillRect(78, 22, 34, 34); - return canvas.toDataURL(); -} - -function configureSource(source) { - source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); -} - -function brightnessPass(start, end, characters, charColor) { - return { - mode: 'brightness', - brightnessStart: start, - brightnessEnd: end, - characters, - charColorMode: 'fixed', - charColor, - }; -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([ - brightnessPass(0, 84, ' .:', '#38bdf8'), - brightnessPass(85, 169, '-=+', '#facc15'), - brightnessPass(170, 255, '*#@', '#f8fafc'), - ]); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - if (!source) return; - - const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); - const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); - const y = Math.floor(t.grid.rows * 0.12); - t.push(); - t.translate(0, y); - t.image(source, width, height); - t.pop(); - drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); - drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('PASSES: 3', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md index 5d53a595..e3c4c05e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md @@ -27,89 +27,7 @@ Dispose of the resource and free associated WebGL textures. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.mouseClicked(() => { - if (source && !disposed) { - source.dispose(); - disposed = true; - } -}); - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.DISPOSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = disposed ? 'Disposed' : 'Active'; - drawText(`STATUS: ${state}`, x, y++, 140, 255, 180); - drawText('CLICK TO DISPOSE', x, y++, 255, 225, 140); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md index 4152fe84..5c1678d4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipX(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipX(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); - drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md index 279b6b6f..3fc50469 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipY(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipY(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); - drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md index 0b03a04b..234bd1fc 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let gradientSource = null; - -t.setup(async () => { - gradientSource = await t.loadImage(IMAGE_URL); - gradientSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!gradientSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - gradientSource.invert(false); - t.image(gradientSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - gradientSource.invert(true); - t.image(gradientSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); - drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md index b417f77c..7357b9fe 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md @@ -23,60 +23,7 @@ chainable methods. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); - video.loop(); -}); - -t.draw(() => { - t.background(6, 12, 10); - if (video) { - t.image(video); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.CREATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: VIDEO LOADING & PLAYBACK', x, y++, 100, 220, 255); - drawText('Demonstrates loadVideo API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(video ? 'STATUS: VIDEO LOADED AND PLAYING' : 'STATUS: LOADING VIDEO...', x, y++, 255, 210, 90); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Extends diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md index 534fb020..0ef2a78c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md @@ -29,59 +29,5 @@ Current playback time in seconds. ### Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let video = null; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - video.loop(); - await video.play(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(6, 8, 20); - if (video) t.image(video, t.grid.cols - 8, t.grid.rows - 10); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.CURRENTTIME', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PLAYBACK POSITION', x, y++, 100, 220, 255); - drawText('Read current video time.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const now = video ? video.currentTime.toFixed(2) : '0.00'; - const dur = video ? video.duration.toFixed(2) : '0.00'; - drawText(`TIME: ${now}`, x, y++, 255, 210, 90); - drawText(`DUR: ${dur}`, x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md index 83cb5503..c31de6e5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md @@ -29,91 +29,5 @@ Total video duration in seconds. ### Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let dur = 0; -let pct = 0; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); - video.loop(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video, t.grid.cols - 8, t.grid.rows - 10); - - dur = video.duration || 0; - const maxExpectedDuration = 10; - pct = Math.min(dur / maxExpectedDuration, 1); - - const gaugeWidth = Math.floor(t.grid.cols * 0.5); - const startX = -Math.floor(gaugeWidth / 2); - const filled = Math.floor(pct * gaugeWidth); - - t.push(); - t.translate(startX, 3); - for (let i = 0; i < gaugeWidth; i++) { - t.push(); - t.translate(i, 0); - if (i < filled) { - t.charColor(180, 255, 180); - t.char('■'); - } else { - t.charColor(60, 70, 95); - t.char('·'); - } - t.point(); - t.pop(); - } - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.DURATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TOTAL RUNTIME DURATION', x, y++, 100, 220, 255); - drawText('Length of the loaded video.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - drawText(`DURATION: ${dur.toFixed(3)}s`, x, y++, 255, 210, 90); - const pctStr = `${(pct * 100).toFixed(0)}% of Max Reference (10.0s)`; - drawText(pctStr, x, y++, 160, 170, 195); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md index 061ee55d..2d9049f7 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md @@ -29,81 +29,7 @@ Ideal draw height in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.HEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.height : 0; - drawText(`HEIGHT: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md index f58c2d47..64aaa6f6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md @@ -29,77 +29,5 @@ Whether the video is currently playing. ### Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let playing = false; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); - video.loop(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video, t.grid.cols - 8, t.grid.rows - 10); - playing = video.isPlaying; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.ISPLAYING', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PLAYBACK STATE INQUIRY', x, y++, 100, 220, 255); - drawText('Checks if video is playing.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - const stateStr = playing ? '▶ ACTIVE PLAYING' : '⏸ PAUSED'; - const stateColor = playing ? [120, 255, 120] : [255, 120, 120]; - drawText(`STATE: ${stateStr}`, x, y++, ...stateColor); - drawText(`isPlaying: ${playing}`, x, y++, 255, 210, 90); - drawText('CLICK ANYWHERE TO TOGGLE PLAYBACK', x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(async () => { - if (!video) return; - if (video.isPlaying) { - video.pause(); - } else { - await video.play(); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md index 2f750f2e..5c3800aa 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md @@ -29,81 +29,7 @@ Original source height in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALHEIGHT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const h = source ? source.originalHeight : 0; - drawText(`ORIG H: ${h}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md index 89da9300..5cf5f71e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md @@ -29,81 +29,7 @@ Original source width in pixels. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.ORIGINALWIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.originalWidth : 0; - drawText(`ORIG W: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md index 20389f76..62592191 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md @@ -29,68 +29,7 @@ Source element this texture captures. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let texture = null; -let sourceCanvas = null; - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.setup(() => { - sourceCanvas = document.createElement('canvas'); - sourceCanvas.width = 120; - sourceCanvas.height = 80; - texture = t.createTexture(sourceCanvas); - texture.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(8, 10, 18); - if (!texture) return; - const ctx = sourceCanvas.getContext('2d'); - ctx.fillStyle = '#0a0d1a'; - ctx.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height); - ctx.fillStyle = '#38bdf8'; - ctx.beginPath(); - ctx.arc(60 + Math.sin(t.frameCount * 0.05) * 30, 40, 18, 0, Math.PI * 2); - ctx.fill(); - t.image(texture, Math.floor(t.grid.cols * 0.5), Math.floor(t.grid.rows * 0.5)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODETEXTURE.SOURCE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: BACKING ELEMENT', x, y++, 100, 220, 255); - drawText('Texture keeps its source.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const size = sourceCanvas ? sourceCanvas.width + 'x' + sourceCanvas.height : '0x0'; - drawText(`SIZE: ${size}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md index f2803796..0265b4af 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md @@ -29,81 +29,7 @@ WebGL texture backing this source. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.TEXTURE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const state = source && source.texture ? 'READY' : 'WAIT'; - drawText(`TEXTURE: ${state}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md index d8c9f8b3..5d29ff6f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md @@ -29,75 +29,5 @@ Underlying HTML video element. ### Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let readyState = 0; -let videoWidth = 0; -let videoHeight = 0; -let tagName = 'null'; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); - video.loop(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video, t.grid.cols - 8, t.grid.rows - 10); - - const el = video.videoElement; - readyState = el ? el.readyState : 0; - videoWidth = el ? el.videoWidth : 0; - videoHeight = el ? el.videoHeight : 0; - tagName = el ? el.tagName.toLowerCase() : 'null'; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.VIDEOELEMENT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ACCESS NATIVE VIDEO ELEMENT', x, y++, 100, 220, 255); - drawText('Queries DOM element properties.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - drawText(`READY STATE : ${readyState}`, x, y++, 120, 205, 255); - drawText(`SOURCE WIDTH: ${videoWidth}px`, x, y++, 220, 220, 220); - drawText(`SRC HEIGHT : ${videoHeight}px`, x, y++, 220, 220, 220); - drawText(`TAG NAME : <${tagName}>`, x, y++, 180, 255, 180); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md index 9f78426f..39f6e09a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md @@ -29,81 +29,7 @@ Ideal draw width in grid cells. ### Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.WIDTH', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const w = source ? source.width : 0; - drawText(`WIDTH: ${w}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md index 213718a3..eb471e46 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md @@ -42,97 +42,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let sourceA, sourceB; - -function createTransparentCanvas() { - const canvas = document.createElement('canvas'); - canvas.width = 128; - canvas.height = 128; - const ctx = canvas.getContext('2d'); - if (!ctx) return canvas; - - ctx.clearRect(0, 0, 128, 128); - ctx.lineWidth = 10; - ctx.strokeStyle = '#ffffff'; - ctx.strokeRect(20, 20, 88, 88); - - ctx.fillStyle = '#ffffff'; - ctx.beginPath(); - ctx.arc(64, 64, 30, 0, Math.PI * 2); - ctx.fill(); - - return canvas; -} - -t.setup(() => { - const canvas = createTransparentCanvas(); - - sourceA = t.createTexture(canvas); - sourceA.characters(' .:-=+*#%@'); - - sourceB = t.createTexture(canvas); - sourceB.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - if (!sourceA || !sourceB) return; - - const time = t.frameCount * 0.05; - const pulse = 0.5 + 0.5 * Math.sin(time); - sourceB.background(pulse * 255, 100, 255 - pulse * 155); - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BACKGROUND', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TRANSPARENT PIXEL FILL', x, y++, 100, 220, 255); - drawText('Fills transparent pixels before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : DEFAULT BLACK FALLBACK', x, y++, 140, 180, 255); - drawText('Right : CUSTOM BG PULSE FILL', x, y++, 255, 180, 100); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md index 3d69dbe6..e64476ac 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md @@ -36,92 +36,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -const ranges = [ - { label: '0-84', start: 0, end: 84, characters: ' .:-', charColor: '#38bdf8' }, - { label: '85-170', start: 85, end: 170, characters: '=+*#', charColor: '#facc15' }, - { label: '171-255', start: 171, end: 255, characters: '%@', charColor: '#f8fafc' }, -]; - -let rangeSources = []; - -function drawRangeSource(source, x, y, width, height) { - t.push(); - t.translate(x, y); - t.image(source, width, height); - t.pop(); -} - -t.setup(async () => { - rangeSources = await Promise.all( - ranges.map(async (range) => { - const source = await t.loadImage(IMAGE_URL); - source.brightnessRange(range.start, range.end); - source.characters(range.characters); - source.charColorMode('fixed'); - source.charColor(range.charColor); - source.cellColorMode('fixed'); - source.cellColor('#00000000'); - return source; - }) - ); -}); - -t.draw(() => { - t.background(4, 7, 18); - if (rangeSources.length === 0) return; - - const gap = Math.max(4, Math.floor(t.grid.cols * 0.035)); - const panelWidth = Math.max(12, Math.floor((t.grid.cols - gap * 4) / 3)); - const panelHeight = Math.max(10, Math.min(t.grid.rows - 12, Math.floor(panelWidth * 0.72))); - const totalWidth = panelWidth * 3 + gap * 2; - const startX = -Math.floor(totalWidth * 0.5) + Math.floor(panelWidth * 0.5); - const y = -1; - - for (let i = 0; i < rangeSources.length; i++) { - const x = startX + i * (panelWidth + gap); - drawRangeSource(rangeSources[i], x, y, panelWidth, panelHeight); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.BRIGHTNESSRANGE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SUB-BRIGHTNESS CONVERSIONS', x, y++, 100, 220, 255); - drawText('Filters characters by brightness range.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('Left : 0-84 (Shadows)', x, y++, 56, 189, 248); - drawText('Mid : 85-170 (Midtones)', x, y++, 250, 204, 21); - drawText('Right : 171-255(Highlights)', x, y++, 248, 250, 252); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md index fb8ca759..af49fab9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md @@ -42,71 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let red = 40; -let blue = 80; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed').charColor(255); - techSource.cellColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - red = Math.round(40 + 40 * Math.sin(time)); - blue = Math.round(80 + 40 * Math.cos(time * 0.7)); - - techSource.cellColor(red, 40, blue); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CELL COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CELL COLOR: RGB(${red},40,${blue})`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md index 413fef9c..05684d59 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.cellColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.cellColorMode('fixed').cellColor(20, 30, 60); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CELLCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CELL COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for cell backgrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CELL COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md index 86098400..a7e7d3b8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md @@ -42,70 +42,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let techSource = null; -let r = 150; -let g = 150; - -t.setup(async () => { - techSource = await t.loadImage(IMAGE_URL); - techSource.characters(' .:-=+*#%@'); - techSource.charColorMode('fixed'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!techSource) return; - - const time = t.frameCount * 0.04; - r = Math.round(150 + 105 * Math.sin(time)); - g = Math.round(150 + 105 * Math.cos(time * 0.7)); - - techSource.charColor(r, g, 100); - - t.push(); - t.translate(0, 0); - t.image(techSource, 24, 14); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLOR', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CONSTANT CHARACTER COLOR', x, y++, 100, 220, 255); - drawText('Sets color used in fixed coloring mode.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`CHAR COLOR: RGB(${r},${g},100)`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md index af061db6..8ddb0e0f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.charColorMode('sampled'); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.charColorMode('fixed').charColor(140, 255, 180); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARCOLORMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET CHARACTER COLORING MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for glyph foregrounds.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CHAR COLOR MODE: sampled & fixed', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md index 148c4819..abfe6c5b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let pointerSource = null; - -t.setup(async () => { - pointerSource = await t.loadImage(IMAGE_URL); - pointerSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!pointerSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - pointerSource.charRotation(0); - t.image(pointerSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - pointerSource.charRotation(90); - t.image(pointerSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARROTATION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: GLYPH ROTATION ANGLE', x, y++, 100, 220, 255); - drawText('Rotates mapped characters in degrees.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('ROTATION ANGLE: 0 & 90 deg', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md index eefe9d3c..36360e78 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md @@ -35,82 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.characters(' .oO@'); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CHARACTERS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const chars = ' .oO@'; - drawText(`CHARS: ${chars}`, x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md index 5643f077..6b862311 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md @@ -31,82 +31,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; -let disposed = false; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - canvas.width = 96; - canvas.height = 64; - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 96, 64); - gradient.addColorStop(0, '#0ea5e9'); - gradient.addColorStop(1, '#f59e0b'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 96, 64); - ctx.fillStyle = '#020617'; - ctx.fillRect(16, 16, 64, 32); - ctx.fillStyle = '#f8fafc'; - ctx.fillRect(28, 26, 40, 12); - return canvas.toDataURL(); -} - -function configureSource(value) { - value.characters(' .:-=+*#%@'); - value.charColorMode('sampled'); - value.cellColorMode('fixed'); -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([{ mode: 'brightness', characters: ' .:', charColor: '#38bdf8' }]); - source.clearConversions(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(5, 8, 18); - if (!source || disposed) return; - t.image(source, Math.floor(t.grid.cols * 0.55), Math.floor(t.grid.rows * 0.55)); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CLEARCONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SOURCE SETTINGS', x, y++, 100, 220, 255); - drawText('Image source conversion API.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('STACK: CLEARED', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md index a953c174..6558e415 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md @@ -35,59 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let source = null; - -t.setup(async () => { - source = await t.loadImage(IMAGE_URL); - source.conversionMode('brightness'); - source.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(4, 7, 18); - t.background(0); - if (!source) return; - - t.image(source, source.width, source.height); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONMODE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: SET IMAGE CONVERSION MODE', x, y++, 100, 220, 255); - drawText('Sets mode used for pixel mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONVERSION MODE: brightness', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md index 7b7fd366..8ee5ca0a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md @@ -35,101 +35,7 @@ This instance for chaining. ## Example -```javascript -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); - -let source = null; - -function createImageUrl() { - const canvas = document.createElement('canvas'); - Object.assign(canvas, { width: 128, height: 80 }); - const ctx = canvas.getContext('2d'); - const gradient = ctx.createLinearGradient(0, 0, 128, 80); - gradient.addColorStop(0, '#020617'); - gradient.addColorStop(0.45, '#0ea5e9'); - gradient.addColorStop(1, '#f8fafc'); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 128, 80); - ctx.fillStyle = '#f97316'; - ctx.fillRect(15, 16, 34, 44); - ctx.fillStyle = '#fde68a'; - ctx.fillRect(78, 22, 34, 34); - return canvas.toDataURL(); -} - -function configureSource(source) { - source.characters(' .:-=+*#%@').charColorMode('sampled').cellColorMode('fixed').cellColor('#020617'); -} - -function brightnessPass(start, end, characters, charColor) { - return { - mode: 'brightness', - brightnessStart: start, - brightnessEnd: end, - characters, - charColorMode: 'fixed', - charColor, - }; -} - -t.setup(async () => { - source = await t.loadImage(createImageUrl()); - configureSource(source); - source.conversions([ - brightnessPass(0, 84, ' .:', '#38bdf8'), - brightnessPass(85, 169, '-=+', '#facc15'), - brightnessPass(170, 255, '*#@', '#f8fafc'), - ]); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -t.draw(() => { - t.background(4, 7, 16); - if (!source) return; - - const width = Math.max(12, Math.floor(t.grid.cols * 0.42)); - const height = Math.max(8, Math.floor(t.grid.rows * 0.4)); - const y = Math.floor(t.grid.rows * 0.12); - t.push(); - t.translate(0, y); - t.image(source, width, height); - t.pop(); - drawText('STACKED SOURCE', -7, y - Math.floor(height / 2) - 2, 255, 225, 140); -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.CONVERSIONS', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: ORDERED SOURCE PASSES', x, y++, 100, 220, 255); - drawText('Three brightness ranges stack.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('PASSES: 3', x, y++, 140, 255, 180); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md index 91098829..31dd0543 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md @@ -27,74 +27,7 @@ Dispose the video source and release the backing media element. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let disposed = false; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(5, 7, 18); - if (video && !disposed) { - t.image(video, t.grid.cols - 8, t.grid.rows - 10); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.DISPOSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: CLEANUP AND DISPOSAL', x, y++, 100, 220, 255); - drawText('Releases video resources.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (disposed) { - drawText('STATUS: DISPOSED', x, y++, 255, 120, 120); - } else if (video) { - drawText('STATUS: ACTIVE', x, y++, 120, 255, 120); - drawText('CLICK ANYWHERE TO DISPOSE VIDEO', x, y++, 255, 210, 90); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(() => { - if (!video || disposed) return; - video.dispose(); - disposed = true; -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Overrides diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md index c0dae162..557553c5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipX(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipX(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPX', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE HORIZONTALLY', x, y++, 100, 220, 255); - drawText('Flips image horizontally before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP X STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md index 59cb9528..57eb8d36 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md @@ -35,75 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let sourceA = null; -let sourceB = null; - -t.setup(async () => { - sourceA = await t.loadImage(IMAGE_URL); - sourceA.characters(' .:-=+*#%@'); - sourceA.flipY(false); - - sourceB = await t.loadImage(IMAGE_URL); - sourceB.characters(' .:-=+*#%@'); - sourceB.flipY(true); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!sourceA || !sourceB) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - t.image(sourceA, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - t.image(sourceB, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.FLIPY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: FLIP SOURCE VERTICALLY', x, y++, 100, 220, 255); - drawText('Flips image vertically before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('FLIP Y STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md index 74fd65a0..deeb8b69 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md @@ -35,71 +35,7 @@ This instance for chaining. ## Example -```javascript -const IMAGE_URL = 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 8, -}); - -const labelLayer = t.layers.add(); -let gradientSource = null; - -t.setup(async () => { - gradientSource = await t.loadImage(IMAGE_URL); - gradientSource.characters(' .:-=+*#%@'); -}); - -t.draw(() => { - t.background(6, 10, 22); - - if (!gradientSource) return; - - const imgW = 20; - const imgH = 12; - - t.push(); - t.translate(-12, 0); - gradientSource.invert(false); - t.image(gradientSource, imgW, imgH); - t.pop(); - - t.push(); - t.translate(12, 0); - gradientSource.invert(true); - t.image(gradientSource, imgW, imgH); - t.pop(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODESOURCE.INVERT', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INVERT SOURCE BRIGHTNESS', x, y++, 100, 220, 255); - drawText('Inverts pixel colors before mapping.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('INVERTED STATUS: false & true', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + ## Inherited from diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md index 3a07293d..0baf2416 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md @@ -33,73 +33,5 @@ Set whether the video loops. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let currentTime = 0; -let duration = 0; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(false); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - currentTime = video.currentTime; - duration = video.duration || 1; - - if (!video.isPlaying && video.currentTime >= video.duration) { - video.time(0); - void video.play(); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.LOOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LOOP CONTROL & END EVENT', x, y++, 100, 220, 255); - drawText('Disables auto-loop, loops manually.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - drawText(`CURRENT TIME: ${currentTime.toFixed(1)}s`, x, y++, 255, 210, 90); - drawText(`DURATION : ${duration.toFixed(1)}s`, x, y++, 255, 210, 90); - drawText('LOOP MODE : MANUAL DETECT', x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md index 173aef84..9afcf54a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md @@ -27,76 +27,5 @@ Pause video playback. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let playing = false; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - playing = video.isPlaying; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.PAUSE', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PAUSING VIDEO PLAYBACK', x, y++, 100, 220, 255); - drawText('Stops playback at current frame.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - const actionStr = playing ? 'CLICK TO PAUSE()' : 'CLICK TO RESUME WITH PLAY()'; - drawText(actionStr, x, y++, 255, 210, 90); - const state = playing ? 'PLAYING' : 'PAUSED'; - drawText(`PLAY: ${state}`, x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(async () => { - if (!video) return; - if (video.isPlaying) { - video.pause(); - } else { - await video.play(); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md index 6cf6c574..7b84c4d5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md @@ -29,74 +29,5 @@ Promise that resolves when playback starts. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let playing = false; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.volume(0); - await video.play(); - video.pause(); - video.time(0); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - playing = video.isPlaying; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.PLAY', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: INITIATING VIDEO PLAYBACK', x, y++, 100, 220, 255); - drawText('Plays or restarts a loaded video.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - const actionStr = playing ? 'CLICK TO RESTART PLAYBACK' : 'CLICK TO CALL PLAY()'; - drawText(actionStr, x, y++, 255, 210, 90); - const state = playing ? 'PLAYING' : 'PAUSED'; - drawText(`PLAY: ${state}`, x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(async () => { - if (!video) return; - video.time(0); - await video.play(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md index f70d7c2a..c6a05041 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md @@ -33,70 +33,5 @@ Set playback speed. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let rate = 1.0; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - const halfWidth = t.grid.cols / 2; - const normalizedX = (t.mouse.x + halfWidth) / t.grid.cols; - const clampedX = Math.max(0, Math.min(1, normalizedX)); - rate = 0.1 + clampedX * 3.9; - - video.speed(rate); - t.image(video); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.SPEED', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PLAYBACK RATE CONTROL', x, y++, 100, 220, 255); - drawText('Alters playback speed dynamically.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - drawText(`CURRENT SPEED: ${rate.toFixed(1)}x`, x, y++, 255, 210, 90); - drawText('MOVE MOUSE HORIZONTALLY TO CHANGE', x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md index d13b7818..b58517ad 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md @@ -27,81 +27,5 @@ Stop the video and seek to the beginning. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let playing = false; -let restartTimeout = null; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - playing = video.isPlaying; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.STOP', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: TERMINATING PLAYBACK', x, y++, 100, 220, 255); - drawText('Stops video and resets timeline.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - const state = playing ? 'PLAYING' : 'STOPPED'; - drawText(`PLAY: ${state}`, x, y++, 255, 210, 90); - drawText("PRESS 'S' TO STOP VIDEO", x, y++, 120, 205, 255); - if (restartTimeout) { - drawText('RESTARTING IN 1 SECOND...', x, y++, 140, 160, 190); - } - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.keyPressed(() => { - if (!video || !t.isKeyPressed('s')) return; - - video.stop(); - if (restartTimeout) clearTimeout(restartTimeout); - restartTimeout = setTimeout(() => { - void video.play(); - restartTimeout = null; - }, 1000); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md index a4e84069..52c48839 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md @@ -33,73 +33,5 @@ Seek to a playback time. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let currentTime = 0; -let duration = 0; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(); - video.volume(0); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - currentTime = video.currentTime; - duration = video.duration || 1; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.TIME', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: JUMPING TO PLAYBACK TIME', x, y++, 100, 220, 255); - drawText('Sets a new playback position.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - drawText(`CURRENT TIME: ${currentTime.toFixed(1)}s`, x, y++, 255, 210, 90); - drawText(`DURATION : ${duration.toFixed(1)}s`, x, y++, 255, 210, 90); - drawText('CLICK ANYWHERE TO JUMP RANDOM TIME', x, y++, 120, 205, 255); - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(() => { - if (!video) return; - video.time(Math.random() * video.duration); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md index f15a1a41..8df0baf1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md @@ -33,83 +33,5 @@ Set playback volume. ## Example -```javascript -const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'; -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, -}); - -const labelLayer = t.layers.add(); -let video = null; -let audioEnabled = false; -let level = 0; - -t.setup(async () => { - video = await t.loadVideo(VIDEO_URL); - video.characters(' .:-=+*#%@'); - video.loop(); - await video.play(); -}); - -t.draw(() => { - t.background(6, 8, 20); - if (!video) return; - - t.image(video); - - if (audioEnabled) { - const halfHeight = t.grid.rows / 2; - const normalizedY = (t.mouse.y + halfHeight) / t.grid.rows; - level = 1 - Math.max(0, Math.min(1, normalizedY)); - video.volume(level); - } -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('TEXTMODEVIDEO.VOLUME', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: AUDIO VOLUME AMPLITUDE', x, y++, 100, 220, 255); - drawText('Controls video audio loudness.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - - if (video) { - if (audioEnabled) { - drawText(`VOLUME LEVEL: ${level.toFixed(2)}`, x, y++, 255, 210, 90); - drawText('MOVE MOUSE VERTICALLY FOR VOLUME', x, y++, 120, 205, 255); - } else { - drawText('CLICK ANYWHERE TO UNMUTE AUDIO', x, y++, 255, 120, 120); - } - } else { - drawText('LOADING VIDEO...', x, y++, 255, 180, 120); - } -}); - -t.mouseClicked(async () => { - if (!video || audioEnabled) return; - - video.videoElement.muted = false; - audioEnabled = true; - await video.play(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md index 4cd0a238..36455f1e 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md @@ -50,96 +50,7 @@ Called when the plugin is installed on a [Textmodifier](../../../classes/Textmod #### Example -```javascript -let isInstalled = false; -let coreEnergy = 0; - -const quantumPlugin = { - name: 'quantum-core', - install(textmodifier) { - isInstalled = true; - coreEnergy = 1.0; - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [quantumPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 22); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const angle = Math.atan2(y, x); - const spiral = Math.sin(dist * 0.3 - angle * 3 + tm * 2); - const norm = (spiral + 1) * 0.5; - - const charKey = dist < 3 ? '@' : dist < 8 ? '#' : norm > 0.6 ? '*' : norm > 0.3 ? '+' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - isInstalled ? Math.floor(100 + norm * 155) : 80, - isInstalled ? Math.floor(180 + norm * 75) : 80, - isInstalled ? Math.floor(255 - dist * 8) : 80 - ); - t.cellColor( - isInstalled ? Math.floor(8 + norm * 16) : 4, - isInstalled ? Math.floor(14 + norm * 20) : 4, - isInstalled ? Math.floor(32 + norm * 24) : 8 - ); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('PLUGINS.TEXTMODEPLUGIN.INSTALL', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: NEURAL MATRIX CORE IGNITION', x, y++); - t.charColor(140, 160, 190); - t.print('install(t, context) initializes state', x, y++); - t.print('during textmode instance creation.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`PLUGIN INSTALLED: ${isInstalled}`, x, y++); - t.print(`CORE ENERGY: ${(coreEnergy * 100).toFixed(0)}%`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` - + *** @@ -164,62 +75,5 @@ Called when the plugin is uninstalled from a [Textmodifier](../../../classes/Tex #### Example -```javascript -let uninstalled = false; - -const myPlugin = { - name: 'uninstall-plugin', - install(textmodifier, context) {}, - uninstall(textmodifier, context) { - uninstalled = true; - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [myPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 20); -}); - -t.mouseClicked(() => { - if (uninstalled) return; - t.destroy(); - document.body.innerHTML = - '
plugin.uninstall() executed successfully.
'; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.UNINSTALL', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: PLUGIN CLEANUP HOOK', x, y++, 100, 220, 255); - drawText('Executes when the sketch is destroyed.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(uninstalled ? 'Status: Cleaned Up' : 'Status: Active (Click to uninstall)', x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md index 58bcd0bf..843f77b4 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md @@ -35,75 +35,5 @@ A function to unregister the hook. ## Example -```javascript -let disposedCount = 0; -let layerToDispose = null; - -const hookPlugin = { - name: 'layer-disposed-hook-plugin', - install(textmodifier, context) { - context.registerLayerDisposedHook(() => { - disposedCount += 1; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [hookPlugin], -}); - -const labelLayer = t.layers.add(); - -t.setup(() => { - layerToDispose = t.layers.add({ fontSize: 16 }); -}); - -t.draw(() => { - t.background(6, 8, 20); -}); - -t.mouseClicked(() => { - if (!layerToDispose) return; - layerToDispose.dispose(); - layerToDispose = null; -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.REGISTERLAYERDISPOSEDHOOK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LAYER DISPOSED HOOK', x, y++, 100, 220, 255); - drawText('Runs when a layer is disposed.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`DISPOSED COUNT : ${disposedCount}`, x, y++, 140, 190, 255); - drawText( - layerToDispose ? 'Click to dispose layer.' : 'Layer has been disposed successfully.', - x, - y++, - 180, - 255, - 180 - ); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md index da096449..7471109c 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md @@ -36,56 +36,5 @@ A function to unregister the hook. ## Example -```javascript -let postRenderCount = 0; - -const hookPlugin = { - name: 'layer-post-render-hook-plugin', - install(textmodifier, context) { - context.registerLayerPostRenderHook(() => { - postRenderCount += 1; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [hookPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 20); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.REGISTERLAYERPOSTRENDERHOOK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LAYER POST-RENDER HOOK', x, y++, 100, 220, 255); - drawText('Runs after drawing framebuffers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INVOCATIONS : ${postRenderCount}`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md index 5b23d848..dd561297 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md @@ -37,56 +37,5 @@ A function to unregister the hook. ## Example -```javascript -let preRenderCount = 0; - -const hookPlugin = { - name: 'layer-pre-render-hook-plugin', - install(textmodifier, context) { - context.registerLayerPreRenderHook(() => { - preRenderCount += 1; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [hookPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 20); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.REGISTERLAYERPRERENDERHOOK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: LAYER PRE-RENDER HOOK', x, y++, 100, 220, 255); - drawText('Runs before drawing framebuffers.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INVOCATIONS : ${preRenderCount}`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md index 4f43f9d5..3170b8bd 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md @@ -36,84 +36,5 @@ A function to unregister the hook. ## Example -```javascript -let postDrawFrame = 0; - -const vignettePlugin = { - name: 'vignette-post', - install(textmodifier, context) { - context.registerPostDrawHook(() => { - postDrawFrame++; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [vignettePlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 10, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const dist = Math.hypot(x, y); - const angle = Math.atan2(y, x); - const pattern = Math.sin(dist * 0.3 - tm * 2) * Math.cos(angle * 6); - const norm = (pattern + 1) * 0.5; - - const charKey = norm > 0.7 ? '@' : norm > 0.4 ? '*' : norm > 0.2 ? '+' : '.'; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(80 + norm * 175), Math.floor(180 + norm * 75), Math.floor(255 - norm * 100)); - t.cellColor(Math.floor(6 + norm * 12), Math.floor(12 + norm * 14), Math.floor(28 + norm * 18)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('PLUGINS.REGISTERPOSTDRAWHOOK', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: FRAME-END VIGNETTE OVERLAY', x, y++); - t.charColor(140, 160, 190); - t.print('Executes at the very end of the', x, y++); - t.print('global t.draw() frame render.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`POST-DRAW FRAMES: ${postDrawFrame}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md index 940848c2..35c3ab90 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md @@ -38,56 +38,5 @@ A function to unregister the hook. ## Example -```javascript -let postSetupCounter = 0; - -const hookPlugin = { - name: 'post-setup-hook-plugin', - install(textmodifier, context) { - context.registerPostSetupHook(() => { - postSetupCounter += 1; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [hookPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(6, 8, 20); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.REGISTERPOSTSETUPHOOK', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: POST-SETUP LIFECYCLE HOOK', x, y++, 100, 220, 255); - drawText('Runs immediately after user setup.', x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText(`INVOCATIONS : ${postSetupCounter}`, x, y++, 140, 190, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md index 7562df34..2e4967a2 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md @@ -36,86 +36,5 @@ A function to unregister the hook. ## Example -```javascript -let preDrawFrames = 0; -let fluidTime = 0; - -const plasmaPlugin = { - name: 'plasma-pre', - install(textmodifier, context) { - context.registerPreDrawHook(() => { - preDrawFrames++; - fluidTime += 0.06; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [plasmaPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(10, 4, 20); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - - for (let y = top; y <= bottom; y++) { - for (let x = left; x <= right; x++) { - const v1 = Math.sin(x * 0.15 + fluidTime); - const v2 = Math.sin(y * 0.15 + fluidTime * 1.3); - const v3 = Math.sin((x + y) * 0.15 + fluidTime * 0.8); - const norm = (v1 + v2 + v3 + 3) / 6; - - const charKey = norm > 0.75 ? '@' : norm > 0.5 ? '#' : norm > 0.3 ? '+' : '.'; - - t.push(); - t.translate(x, y); - t.charColor(Math.floor(180 + norm * 75), Math.floor(60 + norm * 140), Math.floor(220 - norm * 100)); - t.cellColor(Math.floor(16 + norm * 14), Math.floor(6 + norm * 10), Math.floor(24 + norm * 18)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('PLUGINS.REGISTERPREDRAWHOOK', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: GRAVITATIONAL PLASMA VORTEX', x, y++); - t.charColor(140, 160, 190); - t.print('Executes right before main t.draw()', x, y++); - t.print('runs each animation frame.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`PRE-DRAW FRAMES: ${preDrawFrames}`, x, y++); - t.print(`FLUID TIME: ${fluidTime.toFixed(2)} S`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md index 40188af3..97fea677 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md @@ -38,89 +38,5 @@ A function to unregister the hook. ## Example -```javascript -let preSetupTriggered = false; -let matrixSeed = 0; - -const matrixPlugin = { - name: 'matrix-presetup', - install(textmodifier, context) { - context.registerPreSetupHook(() => { - preSetupTriggered = true; - matrixSeed = 1337; - }); - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [matrixPlugin], -}); - -const labelLayer = t.layers.add(); - -t.draw(() => { - t.background(4, 16, 8); - const cols = t.grid.cols; - const rows = t.grid.rows; - const left = -Math.floor((cols - 1) / 2); - const right = left + cols - 1; - const top = -Math.floor(rows / 2); - const bottom = top + rows - 1; - const tm = t.frameCount * 0.05; - - for (let x = left; x <= right; x++) { - const dropY = Math.floor((x * 17.3 + tm * 15 + matrixSeed * 0.1) % rows) + top; - for (let y = top; y <= bottom; y++) { - const dist = Math.abs(y - dropY); - const norm = Math.max(0, 1 - dist / 12); - const charKey = dist === 0 ? '@' : norm > 0.6 ? '#' : norm > 0.3 ? '|' : '.'; - - t.push(); - t.translate(x, y); - t.charColor( - dist === 0 ? 255 : Math.floor(40 + norm * 140), - dist === 0 ? 255 : Math.floor(180 + norm * 75), - dist === 0 ? 200 : Math.floor(60 + norm * 80) - ); - t.cellColor(Math.floor(4 + norm * 8), Math.floor(12 + norm * 20), Math.floor(6 + norm * 10)); - t.char(charKey); - t.point(); - t.pop(); - } - } -}); - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - t.push(); - t.printAlign('left', 'top'); - t.charColor(120, 240, 180); - t.print('PLUGINS.REGISTERPRESETUPHOOK', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 210, 255); - t.print('CONCEPT: PRE-SETUP MATRIX PALETTE', x, y++); - t.charColor(140, 160, 190); - t.print('Runs immediately before t.setup()', x, y++); - t.print('executes to seed initial state.', x, y++); - t.charColor(70, 100, 140); - t.print('------------------------------------', x, y++); - t.charColor(140, 255, 200); - t.print(`PRE-SETUP RAN: ${preSetupTriggered}`, x, y++); - t.print(`MATRIX SEED: ${matrixSeed}`, x, y++); - t.pop(); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md index 48f745be..0af20ff0 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md @@ -33,89 +33,5 @@ Remove a method extension from TextmodeLayer. ## Example -```javascript -let removePulse = null; -let extensionRemoved = false; - -const extensionPlugin = { - name: 'extension-plugin', - install(_textmodifier, context) { - context.extendLayer('pulse', function (amount = 1) { - this.setPluginState('pulse', { amount }); - }); - - removePulse = () => { - context.removeLayerExtension('pulse'); - extensionRemoved = true; - }; - }, -}; - -const t = textmode.create({ - width: window.innerWidth, - height: window.innerHeight, - fontSize: 16, - plugins: [extensionPlugin], -}); - -const layer = t.layers.add({ fontSize: 16 }); -const labelLayer = t.layers.add(); - -t.setup(() => { - layer.pulse(0.6); -}); - -t.draw(() => { - t.background(5, 7, 18); -}); - -layer.draw(() => { - t.clear(); - const state = layer.getPluginState('pulse'); - const amount = state?.amount ?? 0; - - t.push(); - t.char('#'); - t.rotateZ(t.frameCount * (1 + amount)); - t.charColor(255, 180, 120); - t.rect(14, 8); - t.pop(); -}); - -t.mouseClicked(() => { - if (!removePulse || extensionRemoved) { - return; - } - removePulse(); -}); - -function drawText(text, x, y, r = 220, g = 230, b = 255) { - t.push(); - t.printAlign('left', 'top'); - t.charColor(r, g, b); - t.print(text, x, y); - t.pop(); -} - -labelLayer.draw(() => { - t.clear(); - const left = -Math.floor(t.grid.cols / 2); - const top = -Math.floor(t.grid.rows / 2); - let y = top + 3; - const x = left + 3; - - drawText('PLUGINS.REMOVELAYEREXTENSION', x, y++, 100, 255, 140); - drawText('------------------------------------', x, y++, 80, 100, 150); - drawText('CONCEPT: REMOVE LAYER EXTENSIONS', x, y++, 100, 220, 255); - const statusMsg = extensionRemoved ? 'pulse() was removed.' : 'pulse() is available on layer.'; - drawText(statusMsg, x, y++, 140, 160, 190); - drawText('------------------------------------', x, y++, 80, 100, 150); - const clickMsg = extensionRemoved ? 'pulse() removed successfully.' : 'Click to remove pulse() extension.'; - drawText(clickMsg, x, y++, 120, 205, 255); -}); - -t.windowResized(() => { - t.resizeCanvas(window.innerWidth, window.innerHeight); -}); -``` + diff --git a/api/textmode.js/typedoc-sidebar.json b/api/textmode.js/typedoc-sidebar.json index 0409ea30..56982b52 100644 --- a/api/textmode.js/typedoc-sidebar.json +++ b/api/textmode.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Namespaces","collapsed":true,"items":[{"text":"color","link":"/api/textmode.js/namespaces/color/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeColor","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"a","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md"},{"text":"b","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md"},{"text":"g","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md"},{"text":"r","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"normalized","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md"},{"text":"rgb","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md"},{"text":"rgba","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"withAlpha","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeColorMode","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md"},{"text":"TextmodeColorModeState","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md"},{"text":"TextmodeColorTuple","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md"}]}]},{"text":"conversion","link":"/api/textmode.js/namespaces/conversion/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeConversionManager","link":"/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeConversionContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md"},{"text":"TextmodeConversionPassContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md"},{"text":"TextmodeConversionSource","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md"},{"text":"TextmodeConversionStep","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md"},{"text":"TextmodeConversionStrategy","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md"},{"text":"TextmodeColorInput","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md"},{"text":"TextmodeConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md"},{"text":"TextmodeConversionStepOptions","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md"}]}]},{"text":"errors","link":"/api/textmode.js/namespaces/errors/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"TextmodeErrorLevel","link":"/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"ErrorLayerController","link":"/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md"},{"text":"TextmodeError","link":"/api/textmode.js/namespaces/errors/classes/TextmodeError.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"ErrorScreenRendererContext","link":"/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md"},{"text":"TextmodeErrorFormatOptions","link":"/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md"}]}]},{"text":"filters","link":"/api/textmode.js/namespaces/filters/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFilterManager","link":"/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"BuiltInFilterParams","link":"/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md"},{"text":"FilterContext","link":"/api/textmode.js/namespaces/filters/interfaces/FilterContext.md"},{"text":"TextmodeFilterStrategy","link":"/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInFilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md"},{"text":"FilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/FilterName.md"},{"text":"TextmodeFilterUniformDefinitions","link":"/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md"}]}]},{"text":"fonts","link":"/api/textmode.js/namespaces/fonts/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFont","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md"},{"text":"font","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md"}]}]},{"text":"TextmodeTileset","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md"},{"text":"cellHeight","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md"},{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md"},{"text":"columns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md"},{"text":"fontFramebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md"},{"text":"nativeCellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md"},{"text":"rows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"GlyphData","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md"},{"text":"GlyphDimensions","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md"},{"text":"TextmodeGlyphAtlas","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md"},{"text":"TextmodeTilesetOptions","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeGlyph","link":"/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md"}]}]},{"text":"input","link":"/api/textmode.js/namespaces/input/","collapsed":true,"items":[{"text":"Namespaces","collapsed":true,"items":[{"text":"gamepad","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"GamepadAxisEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md"},{"text":"GamepadButtonEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md"},{"text":"GamepadConnectionEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md"},{"text":"GamepadEventMap","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md"},{"text":"TextmodeGamepadButtonSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md"},{"text":"TextmodeGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md"},{"text":"TextmodeGamepadStickSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md"},{"text":"TextmodeStandardGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"GamepadAxisEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md"},{"text":"GamepadButtonEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md"},{"text":"GamepadConnectionEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md"},{"text":"TextmodeStandardAxisName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md"},{"text":"TextmodeStandardButtonName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GAMEPAD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md"}]}]},{"text":"keyboard","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"KeyboardEventData","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md"},{"text":"KeyboardEventMap","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"KeyboardEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"KEYBOARD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md"}]}]},{"text":"mouse","link":"/api/textmode.js/namespaces/input/namespaces/mouse/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"MouseEventData","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md"},{"text":"MouseEventMap","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"MouseEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md"},{"text":"MousePosition","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"MOUSE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md"}]}]},{"text":"touch","link":"/api/textmode.js/namespaces/input/namespaces/touch/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TouchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md"},{"text":"TouchEventMap","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md"},{"text":"TouchLongPressEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md"},{"text":"TouchPinchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md"},{"text":"TouchPosition","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md"},{"text":"TouchRotateEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md"},{"text":"TouchSwipeEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md"},{"text":"TouchTapEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TouchEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md"},{"text":"TouchLongPressHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md"},{"text":"TouchPinchHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md"},{"text":"TouchRotateHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md"},{"text":"TouchSwipeHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md"},{"text":"TouchTapHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GESTURE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md"},{"text":"TOUCH_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"InputEventMap","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md"},{"text":"InputEventName","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventName.md"},{"text":"InputEventOwner","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"INPUT_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md"}]}]},{"text":"layering","link":"/api/textmode.js/namespaces/layering/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"LayerBlendMode","link":"/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeLayer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"asciiFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md"},{"text":"drawFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md"},{"text":"font","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md"},{"text":"grid","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md"},{"text":"texture","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"blendMode","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md"},{"text":"camera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md"},{"text":"createCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md"},{"text":"deletePluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md"},{"text":"draw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md"},{"text":"filter","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md"},{"text":"getPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md"},{"text":"hasPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md"},{"text":"hide","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md"},{"text":"loadFont","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md"},{"text":"loadTileset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md"},{"text":"lookAt","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md"},{"text":"offset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md"},{"text":"opacity","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md"},{"text":"ortho","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md"},{"text":"postDraw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md"},{"text":"resetCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md"},{"text":"rotateZ","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md"},{"text":"setCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md"},{"text":"setPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md"},{"text":"show","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md"},{"text":"useTileColors","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md"}]}]},{"text":"TextmodeLayerManager","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"all","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md"},{"text":"base","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md"},{"text":"filters","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md"},{"text":"resultFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md"},{"text":"clear","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md"},{"text":"move","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md"},{"text":"remove","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md"},{"text":"swap","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeLayerOptions","link":"/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"TEXTMODE_LAYER_BLEND_MODES","link":"/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md"}]}]},{"text":"loading","link":"/api/textmode.js/namespaces/loading/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"LoadingLayerController","link":"/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"LoadingScreenOptions","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md"},{"text":"LoadingScreenRendererContext","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LoadingScreenState","link":"/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md"}]}]},{"text":"media","link":"/api/textmode.js/namespaces/media/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeImage","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md"}]}]},{"text":"TextmodeSource","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md"}]}]},{"text":"TextmodeTexture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md"}]}]},{"text":"TextmodeVideo","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"currentTime","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md"},{"text":"duration","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md"},{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md"},{"text":"isPlaying","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md"},{"text":"videoElement","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md"},{"text":"loop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md"},{"text":"pause","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md"},{"text":"play","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md"},{"text":"speed","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md"},{"text":"stop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md"},{"text":"time","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md"},{"text":"volume","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md"}]}]}]}]},{"text":"plugins","link":"/api/textmode.js/namespaces/plugins/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeCanvasHandle","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md"},{"text":"TextmodePlugin","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md"},{"text":"TextmodePluginContext","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"extendLayer","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md"},{"text":"extendSource","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md"},{"text":"registerLayerDisposedHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md"},{"text":"registerLayerPostRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md"},{"text":"registerLayerPreRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md"},{"text":"registerPostDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md"},{"text":"registerPostSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md"},{"text":"registerPreDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md"},{"text":"registerPreSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md"},{"text":"removeLayerExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md"},{"text":"removeSourceExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LayerExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md"},{"text":"LayerLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md"},{"text":"LayerRenderHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md"},{"text":"SetupLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md"},{"text":"SourceExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md"},{"text":"TextmodePluginHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md"}]}]}]},{"text":"Enumerations","collapsed":true,"items":[{"text":"ShapeAssemblyMode","link":"/api/textmode.js/enumerations/ShapeAssemblyMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"textmode","link":"/api/textmode.js/classes/textmode.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"version","link":"/api/textmode.js/classes/textmode/accessors/version.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"create","link":"/api/textmode.js/classes/textmode/methods/create.md"},{"text":"setErrorLevel","link":"/api/textmode.js/classes/textmode/methods/setErrorLevel.md"}]}]},{"text":"TextmodeCamera","link":"/api/textmode.js/classes/TextmodeCamera.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"eyeX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md"},{"text":"eyeY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md"},{"text":"eyeZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md"},{"text":"targetX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md"},{"text":"targetY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md"},{"text":"targetZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md"},{"text":"upX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upX.md"},{"text":"upY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upY.md"},{"text":"upZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"copy","link":"/api/textmode.js/classes/TextmodeCamera/methods/copy.md"},{"text":"lookAt","link":"/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md"},{"text":"move","link":"/api/textmode.js/classes/TextmodeCamera/methods/move.md"},{"text":"setPosition","link":"/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md"},{"text":"setUp","link":"/api/textmode.js/classes/TextmodeCamera/methods/setUp.md"}]}]},{"text":"TextmodeFramebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"attachmentCount","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md"},{"text":"framebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md"},{"text":"textures","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"begin","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md"},{"text":"dispose","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md"},{"text":"end","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md"},{"text":"readPixels","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md"},{"text":"resize","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md"}]}]},{"text":"TextmodeGlyphRamp","link":"/api/textmode.js/classes/TextmodeGlyphRamp.md"},{"text":"TextmodeGrid","link":"/api/textmode.js/classes/TextmodeGrid.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellHeight","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md"},{"text":"cols","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cols.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeGrid/accessors/height.md"},{"text":"offsetX","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md"},{"text":"offsetY","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md"},{"text":"rows","link":"/api/textmode.js/classes/TextmodeGrid/accessors/rows.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeGrid/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"reset","link":"/api/textmode.js/classes/TextmodeGrid/methods/reset.md"},{"text":"responsive","link":"/api/textmode.js/classes/TextmodeGrid/methods/responsive.md"}]}]},{"text":"TextmodeRandom","link":"/api/textmode.js/classes/TextmodeRandom.md"},{"text":"TextmodeShader","link":"/api/textmode.js/classes/TextmodeShader.md"},{"text":"TextmodeVector","link":"/api/textmode.js/classes/TextmodeVector.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/classes/TextmodeVector/methods/add.md"},{"text":"copy","link":"/api/textmode.js/classes/TextmodeVector/methods/copy.md"},{"text":"cross","link":"/api/textmode.js/classes/TextmodeVector/methods/cross.md"},{"text":"dist","link":"/api/textmode.js/classes/TextmodeVector/methods/dist.md"},{"text":"div","link":"/api/textmode.js/classes/TextmodeVector/methods/div.md"},{"text":"dot","link":"/api/textmode.js/classes/TextmodeVector/methods/dot.md"},{"text":"heading","link":"/api/textmode.js/classes/TextmodeVector/methods/heading.md"},{"text":"limit","link":"/api/textmode.js/classes/TextmodeVector/methods/limit.md"},{"text":"mag","link":"/api/textmode.js/classes/TextmodeVector/methods/mag.md"},{"text":"magSq","link":"/api/textmode.js/classes/TextmodeVector/methods/magSq.md"},{"text":"mult","link":"/api/textmode.js/classes/TextmodeVector/methods/mult.md"},{"text":"normalize","link":"/api/textmode.js/classes/TextmodeVector/methods/normalize.md"},{"text":"set","link":"/api/textmode.js/classes/TextmodeVector/methods/set.md"},{"text":"setMag","link":"/api/textmode.js/classes/TextmodeVector/methods/setMag.md"},{"text":"sub","link":"/api/textmode.js/classes/TextmodeVector/methods/sub.md"}]}]},{"text":"Textmodifier","link":"/api/textmode.js/classes/Textmodifier.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"BLEND_ADDITIVE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md"},{"text":"BLEND_COLOR_BURN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md"},{"text":"BLEND_COLOR_DODGE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md"},{"text":"BLEND_DARKEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md"},{"text":"BLEND_DIFFERENCE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md"},{"text":"BLEND_EXCLUSION","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md"},{"text":"BLEND_HARD_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md"},{"text":"BLEND_LIGHTEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md"},{"text":"BLEND_MULTIPLY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md"},{"text":"BLEND_NORMAL","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md"},{"text":"BLEND_OVERLAY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md"},{"text":"BLEND_SCREEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md"},{"text":"BLEND_SOFT_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md"},{"text":"BLEND_SUBTRACT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md"},{"text":"displayHeight","link":"/api/textmode.js/classes/Textmodifier/properties/displayHeight.md"},{"text":"displayWidth","link":"/api/textmode.js/classes/Textmodifier/properties/displayWidth.md"},{"text":"gamepads","link":"/api/textmode.js/classes/Textmodifier/properties/gamepads.md"},{"text":"lastKeyPressed","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md"},{"text":"lastKeyReleased","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md"},{"text":"LINE_LOOP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md"},{"text":"LINE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md"},{"text":"LINES","link":"/api/textmode.js/classes/Textmodifier/properties/LINES.md"},{"text":"modifierState","link":"/api/textmode.js/classes/Textmodifier/properties/modifierState.md"},{"text":"mouse","link":"/api/textmode.js/classes/Textmodifier/properties/mouse.md"},{"text":"mouseIsPressed","link":"/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md"},{"text":"movedX","link":"/api/textmode.js/classes/Textmodifier/properties/movedX.md"},{"text":"movedY","link":"/api/textmode.js/classes/Textmodifier/properties/movedY.md"},{"text":"pmouse","link":"/api/textmode.js/classes/Textmodifier/properties/pmouse.md"},{"text":"POINTS","link":"/api/textmode.js/classes/Textmodifier/properties/POINTS.md"},{"text":"pressedKeys","link":"/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md"},{"text":"QUAD_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md"},{"text":"QUADS","link":"/api/textmode.js/classes/Textmodifier/properties/QUADS.md"},{"text":"touches","link":"/api/textmode.js/classes/Textmodifier/properties/touches.md"},{"text":"TRIANGLE_FAN","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md"},{"text":"TRIANGLE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md"},{"text":"TRIANGLES","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md"},{"text":"windowHeight","link":"/api/textmode.js/classes/Textmodifier/properties/windowHeight.md"},{"text":"windowWidth","link":"/api/textmode.js/classes/Textmodifier/properties/windowWidth.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"canvas","link":"/api/textmode.js/classes/Textmodifier/accessors/canvas.md"},{"text":"conversions","link":"/api/textmode.js/classes/Textmodifier/accessors/conversions.md"},{"text":"errors","link":"/api/textmode.js/classes/Textmodifier/accessors/errors.md"},{"text":"filters","link":"/api/textmode.js/classes/Textmodifier/accessors/filters.md"},{"text":"font","link":"/api/textmode.js/classes/Textmodifier/accessors/font.md"},{"text":"frameCount","link":"/api/textmode.js/classes/Textmodifier/accessors/frameCount.md"},{"text":"grid","link":"/api/textmode.js/classes/Textmodifier/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/classes/Textmodifier/accessors/height.md"},{"text":"isDisposed","link":"/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md"},{"text":"isRenderingFrame","link":"/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md"},{"text":"layers","link":"/api/textmode.js/classes/Textmodifier/accessors/layers.md"},{"text":"loading","link":"/api/textmode.js/classes/Textmodifier/accessors/loading.md"},{"text":"millis","link":"/api/textmode.js/classes/Textmodifier/accessors/millis.md"},{"text":"overlay","link":"/api/textmode.js/classes/Textmodifier/accessors/overlay.md"},{"text":"secs","link":"/api/textmode.js/classes/Textmodifier/accessors/secs.md"},{"text":"width","link":"/api/textmode.js/classes/Textmodifier/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"abs","link":"/api/textmode.js/classes/Textmodifier/methods/abs.md"},{"text":"acos","link":"/api/textmode.js/classes/Textmodifier/methods/acos.md"},{"text":"ambientLight","link":"/api/textmode.js/classes/Textmodifier/methods/ambientLight.md"},{"text":"applyMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md"},{"text":"arc","link":"/api/textmode.js/classes/Textmodifier/methods/arc.md"},{"text":"asin","link":"/api/textmode.js/classes/Textmodifier/methods/asin.md"},{"text":"atan","link":"/api/textmode.js/classes/Textmodifier/methods/atan.md"},{"text":"atan2","link":"/api/textmode.js/classes/Textmodifier/methods/atan2.md"},{"text":"background","link":"/api/textmode.js/classes/Textmodifier/methods/background.md"},{"text":"beginShape","link":"/api/textmode.js/classes/Textmodifier/methods/beginShape.md"},{"text":"bezierCurve","link":"/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md"},{"text":"box","link":"/api/textmode.js/classes/Textmodifier/methods/box.md"},{"text":"camera","link":"/api/textmode.js/classes/Textmodifier/methods/camera.md"},{"text":"ceil","link":"/api/textmode.js/classes/Textmodifier/methods/ceil.md"},{"text":"cellColor","link":"/api/textmode.js/classes/Textmodifier/methods/cellColor.md"},{"text":"char","link":"/api/textmode.js/classes/Textmodifier/methods/char.md"},{"text":"charColor","link":"/api/textmode.js/classes/Textmodifier/methods/charColor.md"},{"text":"charRotation","link":"/api/textmode.js/classes/Textmodifier/methods/charRotation.md"},{"text":"clamp","link":"/api/textmode.js/classes/Textmodifier/methods/clamp.md"},{"text":"clear","link":"/api/textmode.js/classes/Textmodifier/methods/clear.md"},{"text":"color","link":"/api/textmode.js/classes/Textmodifier/methods/color.md"},{"text":"colorMode","link":"/api/textmode.js/classes/Textmodifier/methods/colorMode.md"},{"text":"cone","link":"/api/textmode.js/classes/Textmodifier/methods/cone.md"},{"text":"constrain","link":"/api/textmode.js/classes/Textmodifier/methods/constrain.md"},{"text":"cos","link":"/api/textmode.js/classes/Textmodifier/methods/cos.md"},{"text":"createCamera","link":"/api/textmode.js/classes/Textmodifier/methods/createCamera.md"},{"text":"createFilterShader","link":"/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md"},{"text":"createFramebuffer","link":"/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md"},{"text":"createGlyphRamp","link":"/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md"},{"text":"createMaterialShader","link":"/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md"},{"text":"createShader","link":"/api/textmode.js/classes/Textmodifier/methods/createShader.md"},{"text":"createTexture","link":"/api/textmode.js/classes/Textmodifier/methods/createTexture.md"},{"text":"createVector","link":"/api/textmode.js/classes/Textmodifier/methods/createVector.md"},{"text":"cursor","link":"/api/textmode.js/classes/Textmodifier/methods/cursor.md"},{"text":"cylinder","link":"/api/textmode.js/classes/Textmodifier/methods/cylinder.md"},{"text":"degrees","link":"/api/textmode.js/classes/Textmodifier/methods/degrees.md"},{"text":"deltaTime","link":"/api/textmode.js/classes/Textmodifier/methods/deltaTime.md"},{"text":"destroy","link":"/api/textmode.js/classes/Textmodifier/methods/destroy.md"},{"text":"dist","link":"/api/textmode.js/classes/Textmodifier/methods/dist.md"},{"text":"doubleClicked","link":"/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md"},{"text":"doubleTap","link":"/api/textmode.js/classes/Textmodifier/methods/doubleTap.md"},{"text":"draw","link":"/api/textmode.js/classes/Textmodifier/methods/draw.md"},{"text":"ease","link":"/api/textmode.js/classes/Textmodifier/methods/ease.md"},{"text":"ellipse","link":"/api/textmode.js/classes/Textmodifier/methods/ellipse.md"},{"text":"ellipsoid","link":"/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md"},{"text":"endShape","link":"/api/textmode.js/classes/Textmodifier/methods/endShape.md"},{"text":"exitPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md"},{"text":"exp","link":"/api/textmode.js/classes/Textmodifier/methods/exp.md"},{"text":"fill","link":"/api/textmode.js/classes/Textmodifier/methods/fill.md"},{"text":"filter","link":"/api/textmode.js/classes/Textmodifier/methods/filter.md"},{"text":"finalDraw","link":"/api/textmode.js/classes/Textmodifier/methods/finalDraw.md"},{"text":"flipX","link":"/api/textmode.js/classes/Textmodifier/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/classes/Textmodifier/methods/flipY.md"},{"text":"floor","link":"/api/textmode.js/classes/Textmodifier/methods/floor.md"},{"text":"fontSize","link":"/api/textmode.js/classes/Textmodifier/methods/fontSize.md"},{"text":"fract","link":"/api/textmode.js/classes/Textmodifier/methods/fract.md"},{"text":"frameRate","link":"/api/textmode.js/classes/Textmodifier/methods/frameRate.md"},{"text":"gamepad","link":"/api/textmode.js/classes/Textmodifier/methods/gamepad.md"},{"text":"gamepadAxisChanged","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md"},{"text":"gamepadButtonPressed","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md"},{"text":"gamepadButtonReleased","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md"},{"text":"gamepadConnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md"},{"text":"gamepadDisconnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md"},{"text":"image","link":"/api/textmode.js/classes/Textmodifier/methods/image.md"},{"text":"inputGrid","link":"/api/textmode.js/classes/Textmodifier/methods/inputGrid.md"},{"text":"invert","link":"/api/textmode.js/classes/Textmodifier/methods/invert.md"},{"text":"isKeyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md"},{"text":"isLooping","link":"/api/textmode.js/classes/Textmodifier/methods/isLooping.md"},{"text":"keyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/keyPressed.md"},{"text":"keyReleased","link":"/api/textmode.js/classes/Textmodifier/methods/keyReleased.md"},{"text":"keyTyped","link":"/api/textmode.js/classes/Textmodifier/methods/keyTyped.md"},{"text":"lerp","link":"/api/textmode.js/classes/Textmodifier/methods/lerp.md"},{"text":"lightFalloff","link":"/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md"},{"text":"line","link":"/api/textmode.js/classes/Textmodifier/methods/line.md"},{"text":"lineWeight","link":"/api/textmode.js/classes/Textmodifier/methods/lineWeight.md"},{"text":"loadFont","link":"/api/textmode.js/classes/Textmodifier/methods/loadFont.md"},{"text":"loadImage","link":"/api/textmode.js/classes/Textmodifier/methods/loadImage.md"},{"text":"loadTileset","link":"/api/textmode.js/classes/Textmodifier/methods/loadTileset.md"},{"text":"loadVideo","link":"/api/textmode.js/classes/Textmodifier/methods/loadVideo.md"},{"text":"log","link":"/api/textmode.js/classes/Textmodifier/methods/log.md"},{"text":"longPress","link":"/api/textmode.js/classes/Textmodifier/methods/longPress.md"},{"text":"lookAt","link":"/api/textmode.js/classes/Textmodifier/methods/lookAt.md"},{"text":"loop","link":"/api/textmode.js/classes/Textmodifier/methods/loop.md"},{"text":"map","link":"/api/textmode.js/classes/Textmodifier/methods/map.md"},{"text":"max","link":"/api/textmode.js/classes/Textmodifier/methods/max.md"},{"text":"min","link":"/api/textmode.js/classes/Textmodifier/methods/min.md"},{"text":"mouseClicked","link":"/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md"},{"text":"mouseDragged","link":"/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md"},{"text":"mouseMoved","link":"/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md"},{"text":"mousePressed","link":"/api/textmode.js/classes/Textmodifier/methods/mousePressed.md"},{"text":"mouseReleased","link":"/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md"},{"text":"mouseScrolled","link":"/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md"},{"text":"noise","link":"/api/textmode.js/classes/Textmodifier/methods/noise.md"},{"text":"noiseDetail","link":"/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md"},{"text":"noiseSeed","link":"/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md"},{"text":"noLights","link":"/api/textmode.js/classes/Textmodifier/methods/noLights.md"},{"text":"noLoop","link":"/api/textmode.js/classes/Textmodifier/methods/noLoop.md"},{"text":"norm","link":"/api/textmode.js/classes/Textmodifier/methods/norm.md"},{"text":"noTexture","link":"/api/textmode.js/classes/Textmodifier/methods/noTexture.md"},{"text":"off","link":"/api/textmode.js/classes/Textmodifier/methods/off.md"},{"text":"on","link":"/api/textmode.js/classes/Textmodifier/methods/on.md"},{"text":"once","link":"/api/textmode.js/classes/Textmodifier/methods/once.md"},{"text":"ortho","link":"/api/textmode.js/classes/Textmodifier/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/classes/Textmodifier/methods/perspective.md"},{"text":"pinch","link":"/api/textmode.js/classes/Textmodifier/methods/pinch.md"},{"text":"pixelDensity","link":"/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md"},{"text":"point","link":"/api/textmode.js/classes/Textmodifier/methods/point.md"},{"text":"pointLight","link":"/api/textmode.js/classes/Textmodifier/methods/pointLight.md"},{"text":"pop","link":"/api/textmode.js/classes/Textmodifier/methods/pop.md"},{"text":"postDraw","link":"/api/textmode.js/classes/Textmodifier/methods/postDraw.md"},{"text":"pow","link":"/api/textmode.js/classes/Textmodifier/methods/pow.md"},{"text":"print","link":"/api/textmode.js/classes/Textmodifier/methods/print.md"},{"text":"printAlign","link":"/api/textmode.js/classes/Textmodifier/methods/printAlign.md"},{"text":"push","link":"/api/textmode.js/classes/Textmodifier/methods/push.md"},{"text":"radians","link":"/api/textmode.js/classes/Textmodifier/methods/radians.md"},{"text":"random","link":"/api/textmode.js/classes/Textmodifier/methods/random.md"},{"text":"randomGaussian","link":"/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md"},{"text":"randomSeed","link":"/api/textmode.js/classes/Textmodifier/methods/randomSeed.md"},{"text":"randomStream","link":"/api/textmode.js/classes/Textmodifier/methods/randomStream.md"},{"text":"rect","link":"/api/textmode.js/classes/Textmodifier/methods/rect.md"},{"text":"redraw","link":"/api/textmode.js/classes/Textmodifier/methods/redraw.md"},{"text":"requestPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md"},{"text":"resetCamera","link":"/api/textmode.js/classes/Textmodifier/methods/resetCamera.md"},{"text":"resetMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md"},{"text":"resetShader","link":"/api/textmode.js/classes/Textmodifier/methods/resetShader.md"},{"text":"resizeCanvas","link":"/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md"},{"text":"rotate","link":"/api/textmode.js/classes/Textmodifier/methods/rotate.md"},{"text":"rotateGesture","link":"/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md"},{"text":"rotateX","link":"/api/textmode.js/classes/Textmodifier/methods/rotateX.md"},{"text":"rotateY","link":"/api/textmode.js/classes/Textmodifier/methods/rotateY.md"},{"text":"rotateZ","link":"/api/textmode.js/classes/Textmodifier/methods/rotateZ.md"},{"text":"round","link":"/api/textmode.js/classes/Textmodifier/methods/round.md"},{"text":"scale","link":"/api/textmode.js/classes/Textmodifier/methods/scale.md"},{"text":"setCamera","link":"/api/textmode.js/classes/Textmodifier/methods/setCamera.md"},{"text":"setUniform","link":"/api/textmode.js/classes/Textmodifier/methods/setUniform.md"},{"text":"setUniforms","link":"/api/textmode.js/classes/Textmodifier/methods/setUniforms.md"},{"text":"setup","link":"/api/textmode.js/classes/Textmodifier/methods/setup.md"},{"text":"shader","link":"/api/textmode.js/classes/Textmodifier/methods/shader.md"},{"text":"sin","link":"/api/textmode.js/classes/Textmodifier/methods/sin.md"},{"text":"sphere","link":"/api/textmode.js/classes/Textmodifier/methods/sphere.md"},{"text":"sq","link":"/api/textmode.js/classes/Textmodifier/methods/sq.md"},{"text":"sqrt","link":"/api/textmode.js/classes/Textmodifier/methods/sqrt.md"},{"text":"stroke","link":"/api/textmode.js/classes/Textmodifier/methods/stroke.md"},{"text":"swipe","link":"/api/textmode.js/classes/Textmodifier/methods/swipe.md"},{"text":"tan","link":"/api/textmode.js/classes/Textmodifier/methods/tan.md"},{"text":"tap","link":"/api/textmode.js/classes/Textmodifier/methods/tap.md"},{"text":"targetFrameRate","link":"/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md"},{"text":"texture","link":"/api/textmode.js/classes/Textmodifier/methods/texture.md"},{"text":"torus","link":"/api/textmode.js/classes/Textmodifier/methods/torus.md"},{"text":"touchCancelled","link":"/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md"},{"text":"touchEnded","link":"/api/textmode.js/classes/Textmodifier/methods/touchEnded.md"},{"text":"touchMoved","link":"/api/textmode.js/classes/Textmodifier/methods/touchMoved.md"},{"text":"touchStarted","link":"/api/textmode.js/classes/Textmodifier/methods/touchStarted.md"},{"text":"translate","link":"/api/textmode.js/classes/Textmodifier/methods/translate.md"},{"text":"translateX","link":"/api/textmode.js/classes/Textmodifier/methods/translateX.md"},{"text":"translateY","link":"/api/textmode.js/classes/Textmodifier/methods/translateY.md"},{"text":"translateZ","link":"/api/textmode.js/classes/Textmodifier/methods/translateZ.md"},{"text":"triangle","link":"/api/textmode.js/classes/Textmodifier/methods/triangle.md"},{"text":"useTileColors","link":"/api/textmode.js/classes/Textmodifier/methods/useTileColors.md"},{"text":"vertex","link":"/api/textmode.js/classes/Textmodifier/methods/vertex.md"},{"text":"windowResized","link":"/api/textmode.js/classes/Textmodifier/methods/windowResized.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeFramebufferOptions","link":"/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md"},{"text":"TextmodeOptions","link":"/api/textmode.js/type-aliases/TextmodeOptions.md"}]}] \ No newline at end of file +[{"text":"Namespaces","collapsed":true,"items":[{"text":"color","link":"/api/textmode.js/namespaces/color/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeColor","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"a","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md"},{"text":"b","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md"},{"text":"g","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md"},{"text":"r","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"normalized","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md"},{"text":"rgb","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md"},{"text":"rgba","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"withAlpha","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeColorMode","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md"},{"text":"TextmodeColorModeState","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md"},{"text":"TextmodeColorTuple","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md"}]}]},{"text":"conversion","link":"/api/textmode.js/namespaces/conversion/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeConversionManager","link":"/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeConversionContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md"},{"text":"TextmodeConversionPassContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md"},{"text":"TextmodeConversionSource","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md"},{"text":"TextmodeConversionStep","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md"},{"text":"TextmodeConversionStrategy","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md"},{"text":"TextmodeColorInput","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md"},{"text":"TextmodeConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md"},{"text":"TextmodeConversionStepOptions","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md"}]}]},{"text":"errors","link":"/api/textmode.js/namespaces/errors/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"TextmodeErrorLevel","link":"/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"ErrorLayerController","link":"/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md"},{"text":"TextmodeError","link":"/api/textmode.js/namespaces/errors/classes/TextmodeError.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"ErrorScreenRendererContext","link":"/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md"},{"text":"TextmodeErrorFormatOptions","link":"/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md"}]}]},{"text":"filters","link":"/api/textmode.js/namespaces/filters/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFilterManager","link":"/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"BuiltInFilterParams","link":"/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md"},{"text":"FilterContext","link":"/api/textmode.js/namespaces/filters/interfaces/FilterContext.md"},{"text":"TextmodeFilterStrategy","link":"/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInFilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md"},{"text":"FilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/FilterName.md"},{"text":"TextmodeFilterUniformDefinitions","link":"/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md"}]}]},{"text":"fonts","link":"/api/textmode.js/namespaces/fonts/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFont","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md"},{"text":"font","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md"}]}]},{"text":"TextmodeTileset","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md"},{"text":"cellHeight","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md"},{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md"},{"text":"columns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md"},{"text":"fontFramebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md"},{"text":"nativeCellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md"},{"text":"rows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"GlyphData","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md"},{"text":"GlyphDimensions","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md"},{"text":"TextmodeGlyphAtlas","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md"},{"text":"TextmodeTilesetOptions","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeGlyph","link":"/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md"}]}]},{"text":"input","link":"/api/textmode.js/namespaces/input/","collapsed":true,"items":[{"text":"Namespaces","collapsed":true,"items":[{"text":"gamepad","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"GamepadAxisEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md"},{"text":"GamepadButtonEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md"},{"text":"GamepadConnectionEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md"},{"text":"GamepadEventMap","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md"},{"text":"TextmodeGamepadButtonSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md"},{"text":"TextmodeGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md"},{"text":"TextmodeGamepadStickSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md"},{"text":"TextmodeStandardGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"GamepadAxisEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md"},{"text":"GamepadButtonEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md"},{"text":"GamepadConnectionEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md"},{"text":"TextmodeStandardAxisName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md"},{"text":"TextmodeStandardButtonName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GAMEPAD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md"}]}]},{"text":"keyboard","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"KeyboardEventData","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md"},{"text":"KeyboardEventMap","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"KeyboardEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"KEYBOARD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md"}]}]},{"text":"mouse","link":"/api/textmode.js/namespaces/input/namespaces/mouse/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"MouseEventData","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md"},{"text":"MouseEventMap","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"MouseEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md"},{"text":"MousePosition","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"MOUSE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md"}]}]},{"text":"touch","link":"/api/textmode.js/namespaces/input/namespaces/touch/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TouchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md"},{"text":"TouchEventMap","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md"},{"text":"TouchLongPressEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md"},{"text":"TouchPinchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md"},{"text":"TouchPosition","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md"},{"text":"TouchRotateEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md"},{"text":"TouchSwipeEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md"},{"text":"TouchTapEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TouchEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md"},{"text":"TouchLongPressHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md"},{"text":"TouchPinchHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md"},{"text":"TouchRotateHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md"},{"text":"TouchSwipeHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md"},{"text":"TouchTapHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GESTURE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md"},{"text":"TOUCH_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"InputEventMap","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md"},{"text":"InputEventName","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventName.md"},{"text":"InputEventOwner","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"INPUT_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md"}]}]},{"text":"layering","link":"/api/textmode.js/namespaces/layering/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"LayerBlendMode","link":"/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeLayer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"asciiFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md"},{"text":"drawFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md"},{"text":"font","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md"},{"text":"grid","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md"},{"text":"texture","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"blendMode","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md"},{"text":"camera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md"},{"text":"createCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md"},{"text":"deletePluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md"},{"text":"draw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md"},{"text":"filter","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md"},{"text":"getPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md"},{"text":"hasPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md"},{"text":"hide","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md"},{"text":"loadFont","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md"},{"text":"loadTileset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md"},{"text":"lookAt","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md"},{"text":"offset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md"},{"text":"opacity","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md"},{"text":"ortho","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md"},{"text":"postDraw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md"},{"text":"resetCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md"},{"text":"rotateZ","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md"},{"text":"setCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md"},{"text":"setPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md"},{"text":"show","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md"},{"text":"useTileColors","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md"}]}]},{"text":"TextmodeLayerManager","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"all","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md"},{"text":"base","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md"},{"text":"filters","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md"},{"text":"resultFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md"},{"text":"clear","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md"},{"text":"move","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md"},{"text":"remove","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md"},{"text":"swap","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeLayerOptions","link":"/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md"}]}]},{"text":"loading","link":"/api/textmode.js/namespaces/loading/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"LoadingLayerController","link":"/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"LoadingScreenOptions","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md"},{"text":"LoadingScreenRendererContext","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LoadingScreenState","link":"/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md"}]}]},{"text":"media","link":"/api/textmode.js/namespaces/media/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeImage","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md"}]}]},{"text":"TextmodeSource","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md"}]}]},{"text":"TextmodeTexture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md"}]}]},{"text":"TextmodeVideo","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"currentTime","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md"},{"text":"duration","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md"},{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md"},{"text":"isPlaying","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md"},{"text":"videoElement","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md"},{"text":"loop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md"},{"text":"pause","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md"},{"text":"play","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md"},{"text":"speed","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md"},{"text":"stop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md"},{"text":"time","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md"},{"text":"volume","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md"}]}]}]}]},{"text":"plugins","link":"/api/textmode.js/namespaces/plugins/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeCanvasHandle","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md"},{"text":"TextmodePlugin","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md"},{"text":"TextmodePluginContext","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"extendLayer","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md"},{"text":"extendSource","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md"},{"text":"registerLayerDisposedHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md"},{"text":"registerLayerPostRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md"},{"text":"registerLayerPreRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md"},{"text":"registerPostDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md"},{"text":"registerPostSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md"},{"text":"registerPreDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md"},{"text":"registerPreSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md"},{"text":"removeLayerExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md"},{"text":"removeSourceExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LayerExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md"},{"text":"LayerLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md"},{"text":"LayerRenderHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md"},{"text":"SetupLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md"},{"text":"SourceExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md"},{"text":"TextmodePluginHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md"}]}]}]},{"text":"Enumerations","collapsed":true,"items":[{"text":"ShapeAssemblyMode","link":"/api/textmode.js/enumerations/ShapeAssemblyMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"textmode","link":"/api/textmode.js/classes/textmode.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"version","link":"/api/textmode.js/classes/textmode/accessors/version.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"create","link":"/api/textmode.js/classes/textmode/methods/create.md"},{"text":"setErrorLevel","link":"/api/textmode.js/classes/textmode/methods/setErrorLevel.md"}]}]},{"text":"TextmodeCamera","link":"/api/textmode.js/classes/TextmodeCamera.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"eyeX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md"},{"text":"eyeY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md"},{"text":"eyeZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md"},{"text":"targetX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md"},{"text":"targetY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md"},{"text":"targetZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md"},{"text":"upX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upX.md"},{"text":"upY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upY.md"},{"text":"upZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"copy","link":"/api/textmode.js/classes/TextmodeCamera/methods/copy.md"},{"text":"lookAt","link":"/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md"},{"text":"move","link":"/api/textmode.js/classes/TextmodeCamera/methods/move.md"},{"text":"setPosition","link":"/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md"},{"text":"setUp","link":"/api/textmode.js/classes/TextmodeCamera/methods/setUp.md"}]}]},{"text":"TextmodeFramebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"attachmentCount","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md"},{"text":"framebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md"},{"text":"textures","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"begin","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md"},{"text":"dispose","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md"},{"text":"end","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md"},{"text":"readPixels","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md"},{"text":"resize","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md"}]}]},{"text":"TextmodeGlyphRamp","link":"/api/textmode.js/classes/TextmodeGlyphRamp.md"},{"text":"TextmodeGrid","link":"/api/textmode.js/classes/TextmodeGrid.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellHeight","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md"},{"text":"cols","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cols.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeGrid/accessors/height.md"},{"text":"offsetX","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md"},{"text":"offsetY","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md"},{"text":"rows","link":"/api/textmode.js/classes/TextmodeGrid/accessors/rows.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeGrid/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"reset","link":"/api/textmode.js/classes/TextmodeGrid/methods/reset.md"},{"text":"responsive","link":"/api/textmode.js/classes/TextmodeGrid/methods/responsive.md"}]}]},{"text":"TextmodeRandom","link":"/api/textmode.js/classes/TextmodeRandom.md"},{"text":"TextmodeShader","link":"/api/textmode.js/classes/TextmodeShader.md"},{"text":"TextmodeVector","link":"/api/textmode.js/classes/TextmodeVector.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/classes/TextmodeVector/methods/add.md"},{"text":"copy","link":"/api/textmode.js/classes/TextmodeVector/methods/copy.md"},{"text":"cross","link":"/api/textmode.js/classes/TextmodeVector/methods/cross.md"},{"text":"dist","link":"/api/textmode.js/classes/TextmodeVector/methods/dist.md"},{"text":"div","link":"/api/textmode.js/classes/TextmodeVector/methods/div.md"},{"text":"dot","link":"/api/textmode.js/classes/TextmodeVector/methods/dot.md"},{"text":"heading","link":"/api/textmode.js/classes/TextmodeVector/methods/heading.md"},{"text":"limit","link":"/api/textmode.js/classes/TextmodeVector/methods/limit.md"},{"text":"mag","link":"/api/textmode.js/classes/TextmodeVector/methods/mag.md"},{"text":"magSq","link":"/api/textmode.js/classes/TextmodeVector/methods/magSq.md"},{"text":"mult","link":"/api/textmode.js/classes/TextmodeVector/methods/mult.md"},{"text":"normalize","link":"/api/textmode.js/classes/TextmodeVector/methods/normalize.md"},{"text":"set","link":"/api/textmode.js/classes/TextmodeVector/methods/set.md"},{"text":"setMag","link":"/api/textmode.js/classes/TextmodeVector/methods/setMag.md"},{"text":"sub","link":"/api/textmode.js/classes/TextmodeVector/methods/sub.md"}]}]},{"text":"Textmodifier","link":"/api/textmode.js/classes/Textmodifier.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"BLEND_ADDITIVE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md"},{"text":"BLEND_COLOR_BURN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md"},{"text":"BLEND_COLOR_DODGE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md"},{"text":"BLEND_DARKEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md"},{"text":"BLEND_DIFFERENCE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md"},{"text":"BLEND_EXCLUSION","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md"},{"text":"BLEND_HARD_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md"},{"text":"BLEND_LIGHTEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md"},{"text":"BLEND_MULTIPLY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md"},{"text":"BLEND_NORMAL","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md"},{"text":"BLEND_OVERLAY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md"},{"text":"BLEND_SCREEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md"},{"text":"BLEND_SOFT_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md"},{"text":"BLEND_SUBTRACT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md"},{"text":"displayHeight","link":"/api/textmode.js/classes/Textmodifier/properties/displayHeight.md"},{"text":"displayWidth","link":"/api/textmode.js/classes/Textmodifier/properties/displayWidth.md"},{"text":"gamepads","link":"/api/textmode.js/classes/Textmodifier/properties/gamepads.md"},{"text":"lastKeyPressed","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md"},{"text":"lastKeyReleased","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md"},{"text":"LINE_LOOP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md"},{"text":"LINE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md"},{"text":"LINES","link":"/api/textmode.js/classes/Textmodifier/properties/LINES.md"},{"text":"modifierState","link":"/api/textmode.js/classes/Textmodifier/properties/modifierState.md"},{"text":"mouse","link":"/api/textmode.js/classes/Textmodifier/properties/mouse.md"},{"text":"mouseIsPressed","link":"/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md"},{"text":"movedX","link":"/api/textmode.js/classes/Textmodifier/properties/movedX.md"},{"text":"movedY","link":"/api/textmode.js/classes/Textmodifier/properties/movedY.md"},{"text":"pmouse","link":"/api/textmode.js/classes/Textmodifier/properties/pmouse.md"},{"text":"POINTS","link":"/api/textmode.js/classes/Textmodifier/properties/POINTS.md"},{"text":"pressedKeys","link":"/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md"},{"text":"QUAD_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md"},{"text":"QUADS","link":"/api/textmode.js/classes/Textmodifier/properties/QUADS.md"},{"text":"touches","link":"/api/textmode.js/classes/Textmodifier/properties/touches.md"},{"text":"TRIANGLE_FAN","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md"},{"text":"TRIANGLE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md"},{"text":"TRIANGLES","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md"},{"text":"windowHeight","link":"/api/textmode.js/classes/Textmodifier/properties/windowHeight.md"},{"text":"windowWidth","link":"/api/textmode.js/classes/Textmodifier/properties/windowWidth.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"canvas","link":"/api/textmode.js/classes/Textmodifier/accessors/canvas.md"},{"text":"conversions","link":"/api/textmode.js/classes/Textmodifier/accessors/conversions.md"},{"text":"errors","link":"/api/textmode.js/classes/Textmodifier/accessors/errors.md"},{"text":"filters","link":"/api/textmode.js/classes/Textmodifier/accessors/filters.md"},{"text":"font","link":"/api/textmode.js/classes/Textmodifier/accessors/font.md"},{"text":"frameCount","link":"/api/textmode.js/classes/Textmodifier/accessors/frameCount.md"},{"text":"grid","link":"/api/textmode.js/classes/Textmodifier/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/classes/Textmodifier/accessors/height.md"},{"text":"isDisposed","link":"/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md"},{"text":"isRenderingFrame","link":"/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md"},{"text":"layers","link":"/api/textmode.js/classes/Textmodifier/accessors/layers.md"},{"text":"loading","link":"/api/textmode.js/classes/Textmodifier/accessors/loading.md"},{"text":"millis","link":"/api/textmode.js/classes/Textmodifier/accessors/millis.md"},{"text":"overlay","link":"/api/textmode.js/classes/Textmodifier/accessors/overlay.md"},{"text":"secs","link":"/api/textmode.js/classes/Textmodifier/accessors/secs.md"},{"text":"width","link":"/api/textmode.js/classes/Textmodifier/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"abs","link":"/api/textmode.js/classes/Textmodifier/methods/abs.md"},{"text":"acos","link":"/api/textmode.js/classes/Textmodifier/methods/acos.md"},{"text":"ambientLight","link":"/api/textmode.js/classes/Textmodifier/methods/ambientLight.md"},{"text":"applyMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md"},{"text":"arc","link":"/api/textmode.js/classes/Textmodifier/methods/arc.md"},{"text":"asin","link":"/api/textmode.js/classes/Textmodifier/methods/asin.md"},{"text":"atan","link":"/api/textmode.js/classes/Textmodifier/methods/atan.md"},{"text":"atan2","link":"/api/textmode.js/classes/Textmodifier/methods/atan2.md"},{"text":"background","link":"/api/textmode.js/classes/Textmodifier/methods/background.md"},{"text":"beginShape","link":"/api/textmode.js/classes/Textmodifier/methods/beginShape.md"},{"text":"bezierCurve","link":"/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md"},{"text":"box","link":"/api/textmode.js/classes/Textmodifier/methods/box.md"},{"text":"camera","link":"/api/textmode.js/classes/Textmodifier/methods/camera.md"},{"text":"ceil","link":"/api/textmode.js/classes/Textmodifier/methods/ceil.md"},{"text":"cellColor","link":"/api/textmode.js/classes/Textmodifier/methods/cellColor.md"},{"text":"char","link":"/api/textmode.js/classes/Textmodifier/methods/char.md"},{"text":"charColor","link":"/api/textmode.js/classes/Textmodifier/methods/charColor.md"},{"text":"charRotation","link":"/api/textmode.js/classes/Textmodifier/methods/charRotation.md"},{"text":"clamp","link":"/api/textmode.js/classes/Textmodifier/methods/clamp.md"},{"text":"clear","link":"/api/textmode.js/classes/Textmodifier/methods/clear.md"},{"text":"color","link":"/api/textmode.js/classes/Textmodifier/methods/color.md"},{"text":"colorMode","link":"/api/textmode.js/classes/Textmodifier/methods/colorMode.md"},{"text":"cone","link":"/api/textmode.js/classes/Textmodifier/methods/cone.md"},{"text":"constrain","link":"/api/textmode.js/classes/Textmodifier/methods/constrain.md"},{"text":"cos","link":"/api/textmode.js/classes/Textmodifier/methods/cos.md"},{"text":"createCamera","link":"/api/textmode.js/classes/Textmodifier/methods/createCamera.md"},{"text":"createFilterShader","link":"/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md"},{"text":"createFramebuffer","link":"/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md"},{"text":"createGlyphRamp","link":"/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md"},{"text":"createMaterialShader","link":"/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md"},{"text":"createShader","link":"/api/textmode.js/classes/Textmodifier/methods/createShader.md"},{"text":"createTexture","link":"/api/textmode.js/classes/Textmodifier/methods/createTexture.md"},{"text":"createVector","link":"/api/textmode.js/classes/Textmodifier/methods/createVector.md"},{"text":"cursor","link":"/api/textmode.js/classes/Textmodifier/methods/cursor.md"},{"text":"cylinder","link":"/api/textmode.js/classes/Textmodifier/methods/cylinder.md"},{"text":"degrees","link":"/api/textmode.js/classes/Textmodifier/methods/degrees.md"},{"text":"deltaTime","link":"/api/textmode.js/classes/Textmodifier/methods/deltaTime.md"},{"text":"destroy","link":"/api/textmode.js/classes/Textmodifier/methods/destroy.md"},{"text":"dist","link":"/api/textmode.js/classes/Textmodifier/methods/dist.md"},{"text":"doubleClicked","link":"/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md"},{"text":"doubleTap","link":"/api/textmode.js/classes/Textmodifier/methods/doubleTap.md"},{"text":"draw","link":"/api/textmode.js/classes/Textmodifier/methods/draw.md"},{"text":"ease","link":"/api/textmode.js/classes/Textmodifier/methods/ease.md"},{"text":"ellipse","link":"/api/textmode.js/classes/Textmodifier/methods/ellipse.md"},{"text":"ellipsoid","link":"/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md"},{"text":"endShape","link":"/api/textmode.js/classes/Textmodifier/methods/endShape.md"},{"text":"exitPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md"},{"text":"exp","link":"/api/textmode.js/classes/Textmodifier/methods/exp.md"},{"text":"fill","link":"/api/textmode.js/classes/Textmodifier/methods/fill.md"},{"text":"filter","link":"/api/textmode.js/classes/Textmodifier/methods/filter.md"},{"text":"finalDraw","link":"/api/textmode.js/classes/Textmodifier/methods/finalDraw.md"},{"text":"flipX","link":"/api/textmode.js/classes/Textmodifier/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/classes/Textmodifier/methods/flipY.md"},{"text":"floor","link":"/api/textmode.js/classes/Textmodifier/methods/floor.md"},{"text":"fontSize","link":"/api/textmode.js/classes/Textmodifier/methods/fontSize.md"},{"text":"fract","link":"/api/textmode.js/classes/Textmodifier/methods/fract.md"},{"text":"frameRate","link":"/api/textmode.js/classes/Textmodifier/methods/frameRate.md"},{"text":"gamepad","link":"/api/textmode.js/classes/Textmodifier/methods/gamepad.md"},{"text":"gamepadAxisChanged","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md"},{"text":"gamepadButtonPressed","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md"},{"text":"gamepadButtonReleased","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md"},{"text":"gamepadConnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md"},{"text":"gamepadDisconnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md"},{"text":"image","link":"/api/textmode.js/classes/Textmodifier/methods/image.md"},{"text":"inputGrid","link":"/api/textmode.js/classes/Textmodifier/methods/inputGrid.md"},{"text":"invert","link":"/api/textmode.js/classes/Textmodifier/methods/invert.md"},{"text":"isKeyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md"},{"text":"isLooping","link":"/api/textmode.js/classes/Textmodifier/methods/isLooping.md"},{"text":"keyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/keyPressed.md"},{"text":"keyReleased","link":"/api/textmode.js/classes/Textmodifier/methods/keyReleased.md"},{"text":"keyTyped","link":"/api/textmode.js/classes/Textmodifier/methods/keyTyped.md"},{"text":"lerp","link":"/api/textmode.js/classes/Textmodifier/methods/lerp.md"},{"text":"lightFalloff","link":"/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md"},{"text":"line","link":"/api/textmode.js/classes/Textmodifier/methods/line.md"},{"text":"lineWeight","link":"/api/textmode.js/classes/Textmodifier/methods/lineWeight.md"},{"text":"loadFont","link":"/api/textmode.js/classes/Textmodifier/methods/loadFont.md"},{"text":"loadImage","link":"/api/textmode.js/classes/Textmodifier/methods/loadImage.md"},{"text":"loadTileset","link":"/api/textmode.js/classes/Textmodifier/methods/loadTileset.md"},{"text":"loadVideo","link":"/api/textmode.js/classes/Textmodifier/methods/loadVideo.md"},{"text":"log","link":"/api/textmode.js/classes/Textmodifier/methods/log.md"},{"text":"longPress","link":"/api/textmode.js/classes/Textmodifier/methods/longPress.md"},{"text":"lookAt","link":"/api/textmode.js/classes/Textmodifier/methods/lookAt.md"},{"text":"loop","link":"/api/textmode.js/classes/Textmodifier/methods/loop.md"},{"text":"map","link":"/api/textmode.js/classes/Textmodifier/methods/map.md"},{"text":"max","link":"/api/textmode.js/classes/Textmodifier/methods/max.md"},{"text":"min","link":"/api/textmode.js/classes/Textmodifier/methods/min.md"},{"text":"mouseClicked","link":"/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md"},{"text":"mouseDragged","link":"/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md"},{"text":"mouseMoved","link":"/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md"},{"text":"mousePressed","link":"/api/textmode.js/classes/Textmodifier/methods/mousePressed.md"},{"text":"mouseReleased","link":"/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md"},{"text":"mouseScrolled","link":"/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md"},{"text":"noise","link":"/api/textmode.js/classes/Textmodifier/methods/noise.md"},{"text":"noiseDetail","link":"/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md"},{"text":"noiseSeed","link":"/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md"},{"text":"noLights","link":"/api/textmode.js/classes/Textmodifier/methods/noLights.md"},{"text":"noLoop","link":"/api/textmode.js/classes/Textmodifier/methods/noLoop.md"},{"text":"norm","link":"/api/textmode.js/classes/Textmodifier/methods/norm.md"},{"text":"noTexture","link":"/api/textmode.js/classes/Textmodifier/methods/noTexture.md"},{"text":"off","link":"/api/textmode.js/classes/Textmodifier/methods/off.md"},{"text":"on","link":"/api/textmode.js/classes/Textmodifier/methods/on.md"},{"text":"once","link":"/api/textmode.js/classes/Textmodifier/methods/once.md"},{"text":"ortho","link":"/api/textmode.js/classes/Textmodifier/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/classes/Textmodifier/methods/perspective.md"},{"text":"pinch","link":"/api/textmode.js/classes/Textmodifier/methods/pinch.md"},{"text":"pixelDensity","link":"/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md"},{"text":"point","link":"/api/textmode.js/classes/Textmodifier/methods/point.md"},{"text":"pointLight","link":"/api/textmode.js/classes/Textmodifier/methods/pointLight.md"},{"text":"pop","link":"/api/textmode.js/classes/Textmodifier/methods/pop.md"},{"text":"postDraw","link":"/api/textmode.js/classes/Textmodifier/methods/postDraw.md"},{"text":"pow","link":"/api/textmode.js/classes/Textmodifier/methods/pow.md"},{"text":"print","link":"/api/textmode.js/classes/Textmodifier/methods/print.md"},{"text":"printAlign","link":"/api/textmode.js/classes/Textmodifier/methods/printAlign.md"},{"text":"push","link":"/api/textmode.js/classes/Textmodifier/methods/push.md"},{"text":"radians","link":"/api/textmode.js/classes/Textmodifier/methods/radians.md"},{"text":"random","link":"/api/textmode.js/classes/Textmodifier/methods/random.md"},{"text":"randomGaussian","link":"/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md"},{"text":"randomSeed","link":"/api/textmode.js/classes/Textmodifier/methods/randomSeed.md"},{"text":"randomStream","link":"/api/textmode.js/classes/Textmodifier/methods/randomStream.md"},{"text":"rect","link":"/api/textmode.js/classes/Textmodifier/methods/rect.md"},{"text":"redraw","link":"/api/textmode.js/classes/Textmodifier/methods/redraw.md"},{"text":"requestPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md"},{"text":"resetCamera","link":"/api/textmode.js/classes/Textmodifier/methods/resetCamera.md"},{"text":"resetMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md"},{"text":"resetShader","link":"/api/textmode.js/classes/Textmodifier/methods/resetShader.md"},{"text":"resizeCanvas","link":"/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md"},{"text":"rotate","link":"/api/textmode.js/classes/Textmodifier/methods/rotate.md"},{"text":"rotateGesture","link":"/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md"},{"text":"rotateX","link":"/api/textmode.js/classes/Textmodifier/methods/rotateX.md"},{"text":"rotateY","link":"/api/textmode.js/classes/Textmodifier/methods/rotateY.md"},{"text":"rotateZ","link":"/api/textmode.js/classes/Textmodifier/methods/rotateZ.md"},{"text":"round","link":"/api/textmode.js/classes/Textmodifier/methods/round.md"},{"text":"scale","link":"/api/textmode.js/classes/Textmodifier/methods/scale.md"},{"text":"setCamera","link":"/api/textmode.js/classes/Textmodifier/methods/setCamera.md"},{"text":"setUniform","link":"/api/textmode.js/classes/Textmodifier/methods/setUniform.md"},{"text":"setUniforms","link":"/api/textmode.js/classes/Textmodifier/methods/setUniforms.md"},{"text":"setup","link":"/api/textmode.js/classes/Textmodifier/methods/setup.md"},{"text":"shader","link":"/api/textmode.js/classes/Textmodifier/methods/shader.md"},{"text":"sin","link":"/api/textmode.js/classes/Textmodifier/methods/sin.md"},{"text":"sphere","link":"/api/textmode.js/classes/Textmodifier/methods/sphere.md"},{"text":"sq","link":"/api/textmode.js/classes/Textmodifier/methods/sq.md"},{"text":"sqrt","link":"/api/textmode.js/classes/Textmodifier/methods/sqrt.md"},{"text":"stroke","link":"/api/textmode.js/classes/Textmodifier/methods/stroke.md"},{"text":"swipe","link":"/api/textmode.js/classes/Textmodifier/methods/swipe.md"},{"text":"tan","link":"/api/textmode.js/classes/Textmodifier/methods/tan.md"},{"text":"tap","link":"/api/textmode.js/classes/Textmodifier/methods/tap.md"},{"text":"targetFrameRate","link":"/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md"},{"text":"texture","link":"/api/textmode.js/classes/Textmodifier/methods/texture.md"},{"text":"torus","link":"/api/textmode.js/classes/Textmodifier/methods/torus.md"},{"text":"touchCancelled","link":"/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md"},{"text":"touchEnded","link":"/api/textmode.js/classes/Textmodifier/methods/touchEnded.md"},{"text":"touchMoved","link":"/api/textmode.js/classes/Textmodifier/methods/touchMoved.md"},{"text":"touchStarted","link":"/api/textmode.js/classes/Textmodifier/methods/touchStarted.md"},{"text":"translate","link":"/api/textmode.js/classes/Textmodifier/methods/translate.md"},{"text":"translateX","link":"/api/textmode.js/classes/Textmodifier/methods/translateX.md"},{"text":"translateY","link":"/api/textmode.js/classes/Textmodifier/methods/translateY.md"},{"text":"translateZ","link":"/api/textmode.js/classes/Textmodifier/methods/translateZ.md"},{"text":"triangle","link":"/api/textmode.js/classes/Textmodifier/methods/triangle.md"},{"text":"useTileColors","link":"/api/textmode.js/classes/Textmodifier/methods/useTileColors.md"},{"text":"vertex","link":"/api/textmode.js/classes/Textmodifier/methods/vertex.md"},{"text":"windowResized","link":"/api/textmode.js/classes/Textmodifier/methods/windowResized.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeFramebufferOptions","link":"/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md"},{"text":"TextmodeOptions","link":"/api/textmode.js/type-aliases/TextmodeOptions.md"}]}] \ No newline at end of file From a3e0d9d798df4c800450871603365e219cacab5e Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 00:35:17 +0200 Subject: [PATCH 03/43] fix: replace string blend modes with constant values in documentation examples --- docs/filters.md | 2 +- docs/fonts.md | 4 ++-- docs/layers-and-compositing.md | 8 ++++---- docs/live-coding-flok-cc.md | 8 ++++---- docs/live-coding-synth-textmode-art.md | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/filters.md b/docs/filters.md index 63b03696..b36249c7 100644 --- a/docs/filters.md +++ b/docs/filters.md @@ -48,7 +48,7 @@ The core library includes: Call [`layer.filter()`](/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md#filter) inside a layer draw callback to process that layer before it is composited: ```js -const glow = t.layers.add({ blendMode: "screen" }); +const glow = t.layers.add({ blendMode: t.BLEND_SCREEN }); glow.draw(() => { t.clear(); diff --git a/docs/fonts.md b/docs/fonts.md index 5d7f7cd4..71e2233f 100644 --- a/docs/fonts.md +++ b/docs/fonts.md @@ -67,7 +67,7 @@ Each layer can load its own font through [`TextmodeLayer.loadFont()`](/api/textm ```js const t = textmode.create({ width: 800, height: 600 }); -const accentLayer = t.layers.add({ fontSize: 16, blendMode: "additive" }); +const accentLayer = t.layers.add({ fontSize: 16, blendMode: t.BLEND_ADDITIVE }); t.setup(async () => { await t.loadFont("./fonts/FROGBLOCK-V2.1.ttf"); @@ -118,7 +118,7 @@ Use [`TextmodeLayer.loadTileset()`](/api/textmode.js/namespaces/layering/classes ```js const tilesLayer = t.layers.add({ fontSize: 8 }); -const previewLayer = t.layers.add({ fontSize: 32, blendMode: "additive" }); +const previewLayer = t.layers.add({ fontSize: 32, blendMode: t.BLEND_ADDITIVE }); t.setup(async () => { const tileset = await t.loadTileset( diff --git a/docs/layers-and-compositing.md b/docs/layers-and-compositing.md index 637b6bfd..0e954b42 100644 --- a/docs/layers-and-compositing.md +++ b/docs/layers-and-compositing.md @@ -31,7 +31,7 @@ Create user layers with [`t.layers.add()`](/api/textmode.js/namespaces/layering/ ```js const glow = t.layers.add({ opacity: 0.75, - blendMode: "screen", + blendMode: t.BLEND_SCREEN, fontSize: 8, }); @@ -59,10 +59,10 @@ Layer options include: [`blendMode()`](/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md#blendmode) controls how a layer is composited over the result below it: ```js -glow.blendMode("additive"); +glow.blendMode(t.BLEND_ADDITIVE); ``` -Built-in modes include `normal`, `additive`, `multiply`, `screen`, `overlay`, `difference`, and other modes listed in [`TEXTMODE_LAYER_BLEND_MODES`](/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md). +Use the [`LayerBlendMode`](/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md) values exposed through constants such as `t.BLEND_NORMAL`, `t.BLEND_ADDITIVE`, `t.BLEND_MULTIPLY`, `t.BLEND_SCREEN`, `t.BLEND_OVERLAY`, and `t.BLEND_DIFFERENCE`. ## Opacity, visibility, and placement @@ -150,4 +150,4 @@ Use [Exporting](/docs/exporting) to choose the right export model: - [`TextmodeLayerManager`](/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md) - [`TextmodeLayer`](/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md) - [`TextmodeLayerOptions`](/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md) -- [`TEXTMODE_LAYER_BLEND_MODES`](/api/textmode.js/namespaces/layering/variables/TEXTMODE_LAYER_BLEND_MODES.md) +- [`LayerBlendMode`](/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md) diff --git a/docs/live-coding-flok-cc.md b/docs/live-coding-flok-cc.md index 94ddf374..ca12d54a 100644 --- a/docs/live-coding-flok-cc.md +++ b/docs/live-coding-flok-cc.md @@ -193,7 +193,7 @@ The flok integration supports the full `textmode.js` layering system, so you can ```js t.fontSize(32); -const audioLayer = t.layers.add({ blendMode: "additive", opacity: 0.8 }); +const audioLayer = t.layers.add({ blendMode: t.BLEND_ADDITIVE, opacity: 0.8 }); audioLayer.draw(() => { t.clear(); @@ -219,7 +219,7 @@ audioLayer.draw(() => { }); const LABEL = "flok x hydra x strudel x textmode.js"; -const labelLayer = t.layers.add({ blendMode: "normal", opacity: 1.0 }); +const labelLayer = t.layers.add({ blendMode: t.BLEND_NORMAL, opacity: 1.0 }); labelLayer.draw(() => { t.clear(); @@ -314,7 +314,7 @@ osc(30, 0.01, 1) t.fontSize(32); const FFT_BINS = 48; -const audioLayer = t.layers.add({ blendMode: "additive", opacity: 0.8 }); +const audioLayer = t.layers.add({ blendMode: t.BLEND_ADDITIVE, opacity: 0.8 }); audioLayer.draw(() => { t.clear(); @@ -341,7 +341,7 @@ audioLayer.draw(() => { }); const LABEL_TEXT = "flok x hydra x strudel x textmode.js"; -const labelLayer = t.layers.add({ blendMode: "normal", opacity: 1.0 }); +const labelLayer = t.layers.add({ blendMode: t.BLEND_NORMAL, opacity: 1.0 }); labelLayer.draw(() => { t.clear(); diff --git a/docs/live-coding-synth-textmode-art.md b/docs/live-coding-synth-textmode-art.md index a6933280..513af023 100644 --- a/docs/live-coding-synth-textmode-art.md +++ b/docs/live-coding-synth-textmode-art.md @@ -88,7 +88,7 @@ t.layers.base.synth( .charMap("░▒▓█"), ); -const layer2 = t.layers.add({ blendMode: "screen", opacity: 0.7 }); +const layer2 = t.layers.add({ blendMode: t.BLEND_SCREEN, opacity: 0.7 }); layer2.synth( char(voronoi(12, 0.2)) From 8426d999e4846640b2f167e824da49498f76d900 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 00:35:56 +0200 Subject: [PATCH 04/43] chore: aligned docs --- .github/ISSUE_TEMPLATE/config.yml | 14 ++++++++++ CONTRIBUTING.md | 43 +++++++++--------------------- SECURITY.md | 44 +++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 SECURITY.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..0a6a0c95 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: true +contact_links: + - name: Contributing overview + url: https://code.textmode.art/docs/contributing/ + about: Choose the correct repository and contribution path before opening an issue. + - name: Documentation + url: https://code.textmode.art/ + about: Search the guides, API reference, and examples before reporting a documentation problem. + - name: textmode.js core repository + url: https://github.com/humanbydefinition/textmode.js/issues + about: Report core library and rendering problems in the core repository. + - name: Discord + url: https://discord.gg/sjrw8QXNks + about: Ask usage questions or discuss documentation ideas before filing an issue. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6586cb00..af7daa1b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,41 +1,24 @@ -# Contributing +# Contributing to `code.textmode.art` -Thank you for your interest in contributing to `code.textmode.art`. +Thank you for helping improve the textmode.js documentation ecosystem. -The full contribution guides live in the documentation site: - -- [Contributing overview](https://code.textmode.art/docs/contributing/) -- [Getting started](https://code.textmode.art/docs/contributing/getting-started) -- [Suggest a font](https://code.textmode.art/docs/contributing/suggest-a-font) -- [Submit a sketch](https://code.textmode.art/docs/contributing/submit-a-sketch) -- [Improve documentation](https://code.textmode.art/docs/contributing/improve-docs) +Start with the [contributing overview](https://code.textmode.art/docs/contributing/). For local site work, follow the +[documentation-site guide](https://code.textmode.art/docs/contributing/getting-started). Library changes use the +[code contribution guide](https://code.textmode.art/docs/contributing/code). ## Quick start ```bash -git clone https://github.com/YOUR-USERNAME/code.textmode.art.git -cd code.textmode.art -npm install +npm ci npm run dev +npm run build ``` -## Contributor credit - -The textmode.js ecosystem keeps contributor profiles in -[`.vitepress/data/contributors.json`](./.vitepress/data/contributors.json) and the ordered contribution-type catalog -in [`.vitepress/data/contribution-types.json`](./.vitepress/data/contribution-types.json). Maintainers update the -relevant file and run: - -```bash -npm run contributors:validate -npm run contributors:render -npm run check:contributors -``` - -The documentation site reads both canonical files directly. Automation synchronizes the same generated Contributors -section to every official textmode.js library README. +Create a focused branch from `dev` and open the pull request against `dev`. Include screenshots for rendered changes. +For contributor registry or contribution-type catalog changes, also run `npm run check:contributors`. -## Need help? +Read the [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities privately by following +[SECURITY.md](SECURITY.md), not through a public issue. -- [Open an issue](https://github.com/humanbydefinition/code.textmode.art/issues) -- [Join the Discord community](https://discord.gg/sjrw8QXNks) +Need help? [Open an issue](https://github.com/humanbydefinition/code.textmode.art/issues) or +[join Discord](https://discord.gg/sjrw8QXNks). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..c44d745e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,44 @@ +# Security Policy + +## Supported Versions + +Security fixes are provided for the currently deployed `code.textmode.art` site and the source on the latest `main` +branch. Older deployments, forks, local modifications, and unmerged `dev` snapshots are not supported. + +If you are unsure whether an issue is security-sensitive, report it privately anyway. We would rather review a false +alarm than miss a vulnerability. + +## Reporting a Vulnerability + +Report suspected vulnerabilities privately to [hello@textmode.art](mailto:hello@textmode.art). + +Do not open a public GitHub issue, pull request, Discussion, or Discord thread. Public reports can put visitors at risk +before a fix is available. + +Include as much of the following as possible: + +- A description of the affected page, component, workflow, or dependency +- Reproduction steps or a minimal proof of concept +- Browser, operating system, URL, and relevant environment details +- The expected impact and any realistic attack scenario +- Mitigation ideas or candidate fixes already considered + +Clearly identify any sensitive material, secrets, private project code, or exploit details in the report. + +## What to Expect + +The maintainers will make a best effort to acknowledge, triage, and reproduce the report, keep the reporter informed, +and deploy a fix when a vulnerability is confirmed. Timing depends on severity, maintainer availability, and the +affected system. + +## Disclosure Process + +`code.textmode.art` follows coordinated disclosure. Give the maintainers reasonable time to investigate and deploy a +fix before public disclosure. The project may publish a security advisory or release note after remediation and will +credit the reporter when appropriate and requested. + +## Scope + +This policy covers the source in this repository, the official deployment at `code.textmode.art`, project-maintained +examples, and documentation-site workflows. It does not cover unrelated third-party services, downstream forks, +private integrations, general support questions, or feature requests. From dd069aaf0a81dd9fb8cc2e86fa57aa38db0a5a61 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 14:56:06 +0200 Subject: [PATCH 05/43] docs: updated README header section --- .github/assets/readme-og.options.json | 35 ++++++++++++++++++++++++++ .github/assets/readme-og.png | Bin 0 -> 53185 bytes README.md | 12 ++++----- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 .github/assets/readme-og.options.json create mode 100644 .github/assets/readme-og.png diff --git a/.github/assets/readme-og.options.json b/.github/assets/readme-og.options.json new file mode 100644 index 00000000..20688e47 --- /dev/null +++ b/.github/assets/readme-og.options.json @@ -0,0 +1,35 @@ +{ + "schemaVersion": 1, + "generator": { + "package": "@textmode/og", + "version": "0.1.0" + }, + "source": { + "name": "textmodeshift", + "repository": "https://github.com/humanbydefinition/editor.textmode.art", + "revision": "b037294d3e0abeff074d50b41235015b3f7d8e67", + "path": "sketches/textmodeshift/sketch.js", + "variantSeed": "readme:code.textmode.art:v1", + "randomSeedTemplate": "textmodeshift-v1:${variantSeed}:${seed}" + }, + "output": { + "path": "readme-og.png", + "layout": { + "kind": "main" + }, + "frame": 60, + "darken": 70 + }, + "branding": { + "logo": "default", + "labels": { + "brandName": "code.textmode.art", + "mainTopRight": "OFFICIAL DOCUMENTATION", + "mainHeadlinePrefix": "EXPLORE", + "mainHeadlineEmphasis": "TEXTMODE", + "mainHeadlineSecondLine": "ON THE WEB", + "mainBottomLeft": "GUIDES / API / EXAMPLES / INTEGRATIONS", + "mainBottomRight": "TEXTMODE.ART" + } + } +} diff --git a/.github/assets/readme-og.png b/.github/assets/readme-og.png new file mode 100644 index 0000000000000000000000000000000000000000..c529b89912c227430205cb0ac6bfe7ab7c29959a GIT binary patch literal 53185 zcmb5WcU03^7d9GY6c90tD2TLSL_v|F2uKM*7(tXOC?X{yA|0f6qS9uh3ermilwPDu zje=5zAT9KW)PxdR0wg542S;Y!_g&w2@4Eb3NKl|DFOHW6G{mAJf5D0`_ z^Tr>yA&_6*K_CY`Sq_3%KK#DK27z!uH2=6}=$*DS!Pa1U$A`i2h>eS33y$IYjrEzz zhfgZU&tBt1ie8YpZeLk^|HP_O;|U_Rpz1}ap|q(Ixj`zNc`jf$%CUx>=+vn0Jv z`tyKL+Apjf&t_&!U8%&?Z{&_5WBZ}e#AKK?a#GSfEFFef8j-HRd`YIITNk?=1`h(! zyET1u@Bh~c+bS%3zsL;M`|qshiD{)PRN*NfKYq+fbegEEvgjVKb%Q0YOg1X+_;jAn zO_Hj?1^N{e%%b7Fkwc{j!8>U0weK_YL?nZnlbG?OnU&rCoKBie`3mNYz}lZVGH@DR zw||yL`f<`J>K4)Yp0po%$=zqH+L1kxytS3vRd~1fW+Jx8xZl0oXFff#WTeb8%r>XA zRMKqny^Cd?e~8HImdWsyr&leOq9+YXYaCK#9q+fKh?`U= zog%y03Gz}-^=i~FM=7q{NYqu{dDMS|G++S!{Q6)V$DZ9(v`Hy^!YAE}g}M&v$!Z=t zEBy-PsUs>JSvGP$uII3afav0Et~o+Rfp@^?bx|V9w^2Ly`Sq8ZlENYbm{)#wvT7K;s6uNhYfLwwm%K`9?uX8S+3syKeV4IoFSJzWJIvq|KbiDF)*cT%7(64W) zOnqY}xWuqm05NcG`cDeh{RM+mK#{lbaTgG^&D_0sLFA~ur>qT}SQ4lTQIUE1^IB$4 zTN!#CB?zdd^M!uVI`zA(7;hnoVpldAT6=Ri)%BKt;~^Mm7OPzwIJ@OWjYMYR%#&<#|c;4P9*dwW*13^Y^J zQlkEe)yy*qvR2TtCYxiOU$4h`c?Ix|`h``b8jrMAL(3gM(1Z3=Bo`t<{(s`PSb4=U-*MBtjkq_}?FcT@^g8O6@OS zthYCLO#L3|!;Os8y)l`S zsy8ODRxcKMhVr(bk$riu!Mp4)ywI03Z^ESD>B-w|znN9p-KlGM+?|qRe+3Jyw2=M# zn=ri@yinzcS%^?ALO=U+bwyb3*@m!Qx_UHHN0mXn&SM!f+NQo;14$B$_~Fq8r2PjF zKdrj%?lr7BC;rRRC$UFvJ{ECGW~*8UDL`M5)+>h7-rXbHWcfDky3YnT>m1r( zLpkfg4e0vn8)6queo?!9t%G&eT7QFMv@%E?pU?Vg$|P@>{8PB0+-TBAX(&Ty1aQ?)yvxS;o^!e$C*l*5H8!r>uya zC@EKs#hd~TC>48)Ifds;9!&@5$VV?NbR%?ymF^4=bXq1p^*ngo>3QX;(mj;OYWy2f%+{qRCg6-w6#ZVA;tDxUew1r`He5q zCPNEX&dnUX1R}g3@WF!*pOP+Hy^y~Q9awUB^8M3a_;NAcf$69c1X|gwx{do}o!^tz z2%dATbQ(3AK&66zJUSosvu4hO@ya=AVbeemX_tCTcwpalH8zH!4UbP=vJtsXft{V1 z_yoV;(7yCCCEYOb5;QZzuUEjzur$%{LwRNU>xqD$GS(>q*4J=tR*;q3XH&j{N!-vh!XtK26gQbFXSk&B&RBifMEm$;J zDqK8RTbpuib~u}RUM$-bKUO`}BLfwIyso(MGllvlN|>eWI&aK%<1Yjp!ziO_ELslt zzfhjGkG@ElCwzZG;;V}oq!gr29bW%aTbN7I+~J`w%LWSwD_wLe<^NAeJptK^-G0~Y zI0Yx!c`9f?S+*H{=)>-VA9X3cKt$*l;OS3OE_e$xD^2`X9pl5cXbM#U5pr}kS4`w6 zkCowqgWmkJa`Qm0R8Fog0c~(`sFE~2PNvA5JHL!FBPe1%J1&sNjk!8#X&2HfG9PdrYx&IQv~ zu9^6ZycUE3X9pp?`J<>nE);00=545Gvh5wj-73iH326XtsEv&n^o5LkBEK22jGXIW zHOqgE^w+nDK4VvkKcV@|G&}k(T;yVO57SxkSE%c=!9txqhnMFk26b5=c{!aVjuLa) zD|h29PWoyXBVD2&ybOMJPVPQ?mu~I9ETPy~Bsth&QiIK9ZE*?NP#=P>vd>D30QtieV;r6AwNh(sT{b3J9XS5ph1-1FFrP@od3MXd@k{iX zA~>-@gG}ny;tCB5D}Dc+ml-OsiA}XzV(isKm)QBuLz3PrGaYepv+0UnGz??6w4-=Q zUtO*Ir z54`rfLt)BXIXM6e_BGz(1MmGy-At^t(%dEFuBfupxL}w$awC;NuUi~i{N5$u*VQ3{ z8AP;WNxrl}BgDpA$$+!Q_sVCAbdeNG@x?e2^D#c}ui@qw7`qD^aCZuRgGMS}4H7h^ zWo$KI_)u$0)f|3cW_Xn%t~>WleD_&Vg=Sw-A(@ zX32a;eH#w(A-g=~dl0<$q)tjkC{s{gOI0!QNvDeNus6xv)QmS1) z(J6O!EpDlUGh_7;*7Nk6HY7#36SnREH^Xg89;4}E)kILYB7FlB#r^Z+p)U z!q;Cih$lio%R<@NX%uWKY|L5Vrg1;- z&B%y|H#O^M1~te)H$Bn(ignKtr>;^aUcHaEZXqkTra=RPq`Sp3W&}E>H$VjOd#l-F z>82&e*L(52v5K>dMck_=O7AnW!<60ex`FFVZj99>q8|>PTEyHUqP+GJ-ybcrg>2kt z<&_(jb0?2LZQo~x(rTEQP?s!2UHrCNFfZ8yw_60M9lCTPsTApjs3hzYy+a`}o9y@UPiPVPk{!9XxFV4-|MPcy7$K0b45O|y!z zjnTu&ux8o^sy3RM!>3-Ik3+A9V0?Q%`F~>)q_0JnI{JPsM9|hZdi>rjzUa`W$0jx? zwM3H1l#KeshM7{qHI{i4+6&h>?NRC%cfK7?>z@UkQ}N{7YHEK7l4PXI+VHg_ zP9y--fc4#G|J`Ync|F-$+xg0lW5Z^j(J^**USiW*D={PGU1$1S$lNL(B~Zl_2daf` z7%mS{wsmC|sY41ve2aWMw61=AJ#dvqWUNjQ>1~g8K>DZ|sjyC_qAJRF>h`&SA`$pb zzTeidbR^w!ay>y#*7WR7yw68A^DL|qYde zlE}ceE*C6PC*#8E6ag_`PMQ!(KGzo@clfEKfGpTbxODz5-=L<~;66E3@k2 zGETbcl2x=s#8tb^_pnKLo7Smg7n`oRG4eUcra+w&c$t(6ITZto~YLNwZz+CU9SwUJYJhy?QD|fPwE3 zW_=^9VuT3Lru0^AY-0>`p`d~KaF0AKi17RNVG7O>=axNtUHt}a8s3ELNo&FR?956! z%U&O@cBEpP$dPWCfKThQT>_New{xqaDJU)Fh=zshk}OKbd<&mAbwRXnCsX0`yIaW8 zODwYXLq&;=ORI88v4}Ea01>HWglC6GynucCJ_(XCpGV7~f%p5B2{ z8sbydWdzO04e<$-QP|ffX5HVv$;r`5UeDJJ7#L^h)9;k}2DqwZvGrJ^_VQB|7S8VTlu6~;;Tl1nx0WkhrnNheIag^k+7>(r*1@c5T=BSjD-J4v@f|vAwHpvshffLC z!@%{5)HR?iP99^UdZ)?3!Y?LQ39$$Mx$*bmWGl z39?8wZOfO(_)95ne7Rn}Tgsq>IQviEWSr!dRFIxat%|&l!OjgeCJFM%KxFQ zZ+6GwIB0MO?51);d&-RXYBL)uzlIEwrS3YamI2LXY)2#A;;V$ArGZ?1^$*|;J}b7{ zZUt~!ia*r(vA!H(q=&~kO@fW+KM&ta)wjnG{Kz*=#6yZ*|yYLkf zY2dds)Ah7-XfKLMc6xfOz=x!l4fuwQbmv=)Wby@^@1i4$v5T%RAw_vL+-Z^@>K)sy z#RSmFV?-$x2rd3IM~6PvJ-~Iqam2N7t6&b`?r;sIhu2+K?of7rT>(!X>wn~iK%G~^ zw4hd^C;$V1RS>d_tDDO$*l;j}l)rS*Fw2$Q6+ATC7t>U=UdP;afqDm~B;pW#*_TCT zLRWOxGBR{NxXkT%LLxgQvco}2-Vd;{BV@{qR>C~fRJj$@v5uY#H)~^7{iTjVum?bv z!B)D(=TQO;Uc};_j93wyzCFJq8GsMhRa$$J`%vNh@4F@FKpKugQxsrq!vj8xNr0TO z${pH*{y5;W$q{9|*B6vX!VX8>>DLiKDQ$rh-|Y|YQKkx=`*Mg|X(h=rszchc?cSaC z7QkIUEz5lh4F+^grCwm2tE!Rga3kmp(TAA@w->4`TGS2Lk!0($fyvcRI+$y7Vat-* z4N&B^WjHq~{$d)Eo{dp*d+G3KYX#<-G6Z+940sgitvH)b+zq3yjHO@nUo^ovyTzMkp=A^;cMxHS_|{gQ?=wjWF28Yhpb7w9NbY+x@9P%zeb|*cNAFOZoejh_ z1psc{*;ufirmB^E*|_!At5W-L%V?PF&Xf1nm<-_y<5l)XU6Grco5G4*GTeyR+K>Se zt8@Kv@jc^&MCA=P%>PBaBhO#&i*@i)v9T@irPkaT~y8KdR6-A9y7e9pm60jtUg z4wJw$n@L$#Y^Y?tLS3Cx5|4D6hgUw9k66AKU8I?ASj8J5zkN7>Y?Qb`$2-5i;K#`J zY&D2$D!wvKb4Q+bYCrLZ^99XY_nm5E+WMm;mJiluF&;=I3n1MXiYX0}HRFLx(+Kj~ z&?;Y*zi0R%zd;ieE-fAq0aTE{+T;C)a>lmx=zq)OInvyi%NRdlAGW>om z@ywYs6s#Zi# zG}wZEr9ADAD)dgbxCXzB%hxPs^j0G=K}HwpJHDD}d7H9IiDsrwY18m1<&_ak)4c>a zhxhny=fJ`P5cj{@l;#>hdXp({@Ff`>;W;x?w;1cj89D#Eu7YjP(ny8Ya==qvEhIBpUad8uJ@58VgJf~0FDQH?w$qk&Jg}GaOW3o8l>(?e{=9HRa z+c%qtmi+6T>0hQd>f+NTZzlTr-WTkAmU;JPuBJ)#xGxC)a{DD(q70tC$h`YPtf}d7 zH#AmnB@VUwXOZTLs#;@MQ}G9i!&k(E)90yiLX?XBuFa`#f2D;s`JHyhgY7W(@j#vR zvwbmoWfgI{l@8 zvyaw{n$|x*L{IG$A|`f+YMNTi5!>t@H+`UHJQuc}NmV=d-XY$uqN_n5z2`x;;O0{r z-X>K8ED?-PtH1>QDe#n#=0+b5-3%7l&8JIDYRl33GRlA76_{R(loJtZJO{|GISwKNXrNrRgrFgHrXjKYE{w{;eebm3rdjS{=6WJk8o$G7YU<+tqRFo&2tX_vS{% z){?dIMplkhhnfriZ7JXB)01^oNK8fxLXBU}X*bzgf-)zEw&PQ#uj!VWQKcK_3{aGX zwKl>^qoR%-J=#7E=!1DU!!{rrPZzPO_gubNQqq-D zH6*N03my~*iUa;gXiR(uA^~A9+t<@3CfGciKf2z z@YEqwB#mNUO0!)r`AX**rjwl!^PQaLl)l6TWM_l*xkXs#6E*qn6d5tcGMD8?`Er%c zxF%3FvgcNz!gVK?noX_NQDlWw3NnMiRNhgcxG1hT%~DC2nRe#K}fi zP9CQL&k?II-uYN~FOE9tm8<47I^(w-LjBH-PTRFUwk4u8^*tOlx%%t%#bs@Y(@krw zh&_}my@edzoe_b5&nGUXj=Vcp%VtYsLwMU#l7)9p#rT&rfnKo#4yTSp=jJlas`rZv zi?n8tin!aEdCeYo;g0f=Wm>xie}yhKh(b zjU(Nfxrss#x8RZVgJU~4Pp?W>lnbKBg3vNI=xA))r(=hCBN~N!S1t@R$9-_HjsCw- z79}gE`1mL0>qO;04!k?Z|E$-oIDwb-SLK1sMv;*f{cZND1`Tbt_3>;`eYMa~oO|ee zSst&Q&%nqb`RKY;-V6CTp#0|N;j)#s@}@5&az-AGhgGiGi`gAM_zOX!RU{tM%I`1BUb2rzwA)rmw}`%CP_4EPy1_fjoCR zl=r5`u7HeqyIXWt<#Hw`pmBFA;8Zrw{Ned_2~m6=n~wuqzU>&h&np_=9X(x#9FdB; z5Rn(IrvvxK1ilP$r{Q-WE3+`7VG-JL34~mobi1cz4`~#VJ}I1AkWQ|$f9QK%dtQ2< z3s97gptO3l(1$02R7Jw1AAga$w3M&x-c=7fY>Px9>l*9^3*3D`v}j`&oc88&3L=1h zwyZ0n9+pYxyNP_fT@<9Ccm!E&&oh|<7Y-AOPni&`_gEZqug$Am{V^B^+F?HtA6??ZVg-}tJg5@CKUMa4 zpvMEyuqx#gZNqqQZwU8c4#P_8xa}=>zbyat%HBA^<&PG(X0m8@m|j0ExEVfVJSCj@IUgaY{5wk!<}K-pEN}5XMxNEOp1JFB^m)6|Ew}Fdd-eNgGGBL5 zC|I5H2kl+~MopdTB)E|4JZ>W)VrQW4W!9%1bnn}2U~+Hjh^m6wz%rlltEOv^1@rx} zs&KI7FL+LpWxlfM4O!7M;dSNL{;$cpuhJ9*wT2dbU`4t#O&NT{Z|#+sdCOb*swQ$lJX_}D%BxRMt~Eq zyLH5#J#;tf?J_8MU>1+HGs-eor{!p;_F4HzR`Yv}yWrQGL)fybow1u_`kK84*}(|V zEIB*@;@vU`pgGu^BYhs)S8c>A|4<&7utFA2XkvnUdN(Nw&WIbaInq~2P!wX+w_qk2*XYN0>I3~^W7cT?u$s>zmmx3BrFTN1nrBQ&~_uQ zV+{4Yj*ceIjVS-e5lBU*wU-G;6unj=3KBP70za@Zt_7udX8y%Vv7?aJz9o(1(L9P9 z1}0a~G**MQY>RTQJ<_pU?Kq|t5yHl;?g$@RU43@|VhG)zZDz+QLRoWW(iUkA&WZd-e zU&?@)+=whRKi<4LFXl-lPsce5r~-3W9r}Ad8D6|U3nj>$Lz(`}~CgdcvM+KQg8dsm$Ad z{m;hFYUHqkKPq5vvJ zJj?-J{XY*90Sms|_WI3p@_5jjkY$a158#T9ZcL9Ue#w3i(y8)K!2OVNz4v7?^IRF{ zxr4UHmV7W7sc}aAHBwlnkAC?12oogz$#NA|eGuihQk$dmP!I(SnA2q?90%G*=}Ql{ zME=*5&JN#m-NY|>5C(uUCes~^^bdc|%w|%t7XQb7W{A>eK@^840^!{#96Uv>u;`Y|RL|E#L00aWx z4}~+wRnwVAyM)q%eLv}6Qc$o1l}y@G#|Dv-+mzm{!F32?$o$h`2YzME?18ixT&s*z z7UOe0m-Hhz^CNA09t1s=el_B0pvC3KcR^o&|I3X zcrw-OUK{bq6&N!|tHK%+RUjxJAPad)5ZbScjZ>k#StU=%Bi0&&V}E_$3sNh;;69*s zI`#hRrGu{xz##AV9Rvnj7^7i3-5Pl=VnXhexg@Ivm~D?R9Dt_D-nK+s4}qZo+VO3d zNsW_C@t1VPL~voyqJJZ@7GI`$J!9?00Z_3@D!WlfZkFdt-$BZrG8e3ekB|i+y^Z_% z@W>68kc=8BxL=9t&>{)))JbF~Lx*g79wo+lG@rTk@C5V8KEXXq5{BK+@3S{qJOpec z!`zP(e%1I4X!HY+*8)pvy-ini0~AA|FCKy99ozQ;)1Q`|$;2E9OJn^hxC7PVMdRlS zfZa(Alae)h)09E_az+D2n*B$Jc2WsyaYN@vthzS`vua}(*JRZOGBYavE;fTjP-`zH zN{yfi6!KK?A5-aT@SpSuslX^JnhlM-h5@P4kMPUnR8>41SG)bF5hjV?Cr~LAEwK`w z!hN+$Ah>AuL~R3=cf}$S1H4^j%vn) z)7tmX+E|=>zxH8BtHQpqjtK`hXVh>&o>F4`bw&J2USZ;Y2_0zB{izg-OM7?3UC{6b zaxdQsn(OW#Xeby+UdXODL^1`Q8Em&L^Z5ZkD*M#Kx_oP6poVjU{5J&R#W7 z`opRrN6NpEo}90i((P0NOTf3&@23iS+9zO{h-e`$(ZHaJ3Og6R_V zb%XV-iPH{$<7E#*%gDr2`f}UQnP6CyO?4#)r0&;!$7oaM8QkFL(@hezUi?uK3XKKJ zf8_6kws_{tOcowe(R`$VM5F&WQ*RGM^HA3V)b*b}OCtf{)D??|6-^E!54P!#3W<|G zESd)o4DjrKN@<47jXk(!mT}2az2&X6bClo%M!{ghU25xNbus3!bse1Ytn&-n6=b`|TnAr+_Jz^X`F-c75FdpMSK3jXBNk z%8w<-(mnP*%3V=Wq*8L3YeEssul~J-xZqv^`$_}%b6l~pgPG>2>&N8XwEnh{A0gZd z_i%(7hx}Qd!;2H?DifDZ6;@CYDBm9kT>l53rw9jwP9y!~n6?qhw`b^w+|Z~(Ic)-V zFJ!a40&hbdnf~+fEw%%%dH3O5E==KnbrR5-ZKS1Z>Bhp#yUdZvya5` z{~DeM_#+hE5)A*uOQn>Q#@~V9vlDr-?*NCHYEFvXJq1xA0njB}5a{k+X{Al4H^wx^ z&PX9|CjT4U|L^8@`*Nu*=^YT0Rh;Nd>G2de2QQ5Xc&PtO79O9tt14!L$@j8Fb(hi%e{>E5MirBoN!7Bk znps?6wGWG>+vkUiZ{d0hhs}WKY(yCd!ha;Vf2)HGPv?1A5%yutq8egTt$W`@JyQ$Vfmm=yNT?QZe?!E*IIl_l(lTNxm@wZZ{2`uC1N z2<7WneazeHJsD`ya$Ap@_e$-2O42enfcv?-^ewb*qM6TYonvMj99gu5|Goxa8uu72 zST*;#(BfAeA?y6V0VvU-QD^uCp?`xIoql9)q$!=llc*HzxfeJ47|4)VVpe~j3!h@3 zBY)P6jL{Wc$~a)e$V`%V%XwzPukObL`BN!7fDrYOV+V&Q?^eqzeOp_tXBeQbP{r^l zM9J9St<%DBlLoj=_LErrVr4QiP&E~HE3+tbg9D;x9s5gbl<|wK;E2mdAeJZh^A-lU zub@ZBbd+Mx6<)7_Jx{Ul+29)L1|vQT2xLN69e)(n_^z}RW2gyaz@7#F=@G<~uowX} z8QTw4|IZRcBIv7qUarASuG@i5wTuQ-KPr82Bb{NhGq*PQ1tAOS`wg&mQ=WLTg^zqD zY)G{EbC2dv{zGPwwj^$dWc-c%xJ)Ez&-yMcoVLG$A?HgLWHd?sS4}Vyc~*yd*O1mL z(<%D!zg(g$(eo|}hI{be1tHFd#Y4wNB>3`w`Nh?)1aW)gY|Px~e8%5~D^;Zdd^3N0 zY)?LzOyx8|3@8PsuTyahWi!v&XA1J}-D-c5v;P|u5M)Bi!ES)gA+@11(J>Vbe>=HX zwYiAHbrRmgj&Xe}u&r$cfC9>I`@paYGw(Q3{@E?Wtll&Eu6yLljm&^26A z+G67j(PQQm(a}l-@a6uH5rc%ospa{RJHHXu`u*-4#*)o^&XY#|k9Z*7Z?x#yz9+cM zI_zcd*SsMSgyh`4cIRnX@P0$p1}}XrPOjfB5AYk;H_{P>1y2D-aNJX@0sOvDISg2% z$Cl}z@w?&-%CJB)old`9qpSPChqM_4N<|sTk=7{+7Aal>ozfb&nS179UjUVio;fQi z$is7KO_}l)n(jH;@M!A8Gp1Hb@AkAH1J`9vzR3hxNaGS@0b3w5p)z|={@$7S-QA^~ zpXo%C>!Nq>CcYnbXitjQ1r64gMqLl*(n-Gj*(2Vq$M`V>!han^6ZrWlL+4Jm-E#*4 zzkX*2tZu5TxY@DfxF1bFC<lfWEUz z@tO+J1#>6HsKJxfZ=gHz9F=!6Juu&kCKVI?7t|OJpGv%>3q%USmCepG{jn2&AGIqG zFwJXp`a~E=-#`pf;k{S3WGi zhF47da4^S0L=|B-S7{a#H>(zQ?CqkTukU^HngNP^Ni7*nqatk2n%oy9ehtYDXNLuQ z9v3zBd0i-A8NCv81RtH%G)yU&+PUzfQGR+g7p2S?wv3iJS@GZ_&tb^Z8~k*Y;TTTk z-KqJ8DfZG!Co4RcF$}UZZhZ51{FWk+5H)S2i-~AGQBD$MZ09zu$CoCbp)xHm2bXdK zFPH*5MvHasn2e8DG`+iZQQX;QT2rK3)^Y1EUH>_5^zcHRA*#{o!aTooEiGyw_nF$% zN`u=NP}@oH#jNW%6WdGHwIACFquIm z<$NMnGO-la@eZwA2B?zITb6BcR|>*Hh1c80O}Lb==yK3zAQ6D1S}ni{0P{R*_1N8FycA z%jzgF2&=*UB_cp%sIa(yDz2eBjg*JgNx&!z*>K8N1v%Up&VOXUhyzp0 zi4B#W`2GXM4Txc-SZwPT4eXwLXanoq<3Hz3PtY^s)@`WVDaf=kbMXM7zq-MAFXc@UzP0rNWy0rS3Zf5wUECYac6&>DB)SV&1|D&3cGiIWQzZ9uY~n-pO?(^daief z$Q6|#?mD4qp8byN^WJn{S5=7RFpxTLhfCD;8h+VABS}C!&aHK>X1siM3JP!Yuzn3JnH6`>z@PTRL#E#a{a3Xr#R_)e2LcNf>*6fFVjutpbib4&?5oxOF4Npz1X zd~M3crDU@wEO^Kze&42?Lasr_?atR#&KkSvHvIxoN#$RA);oCiR3FU7I!Gcn&Gkh` z3TMy~5O=Q5Qyf4?hlu~f8Jr`)n@D6VU{s3G}iwC0VneD}`yyz*i) zrlI}L#wfPQr7OY2N`8#qRi#R>tU=|{g`mdkDcFYQJIRmmU`Y`xt$j#214zxY7gBM% z1@>%mxP~87{>8pW3=@GF;FElOd`EGD-3F-f74D{09;|vS^92TKfIMaPjb4BB*h=x- znz3CYgV!cLeuqx@`kN|2+e;a3CFaK&$5PGoeG|&A-RC^DG?Y0t<5kV5L7WTT_a|=DRh`8`|k;IX<%F| z?2o*n+X%NTOSOI|18W%DVV0A6EG!tax9I^p1lBymT#lXq9_1hfc^Y*AsF~8)Ctce3 zkqrk(Ua60QeC17a?m58C>68RqgY&`%2|MILUDe!&3~%kphWkuh7Ev^VQ0CM-bXY-{=~LzVVRZ>>o5Y_A-^2- zicSPc^UfPlqfTRDhL3=7Jp>_vkMb8P$C(-(* zx4^F(yOpTf=#0to{5mV?Amm)-3|=%FmOWb}(@{2qp4jzjI0H(VLuX*Z*7BH9tCJUg zDl+G^`u*zV5$OerTJ@}8b}}PIJE|-;>X}49_B!@fzcyaK(~Ra?GwyoJx4v~TM6#iBDpLpks>F;sZJ^`Q!=2thZU0h2 zQFBl@vQUGjv17O;V(ZUgkMPJCI-_U1RD0w<6v#s@TpfgUeM6UP(g+DYEcrkY3%bRH zcifE&Z%Z&oQ9EDSth*JydVJo5j^ykj+d&2CU*E$)X2QG!T_ftE%jO-8^jS%y3}94p z63@-EpeO@qExMZ-P1~756)V~H?GLA~5b5L{46?*!5lEJi40;YX`_XZG(3a$C9?x@Y zPLMt|e}Wn^SdRWSN|)?C$fBWo@2T)5U{w^MZnI%SU?d@Fob>0my=^`ZW)h__Z`0JL+y?FRE*HyrV z@$GB*UzFy}nH0lKsvVLSZ)s&^T3>#{E7j11rwhZuYIS0XG1v?Z_?(7Rzw7n`XMfOF z=dH%Aj}gD9-3Z9|d*QHh%pO54FhWyKwqClWw=U%QVpKg) zcoU~{6I-LD1eo!#jCWDS)Tf94ZuDNf`lVuH9+hzM3s9Vx0q*M;0=3a*u)z#a45)9 zoK-X>l2GR)>RtyqJ4d)=l-_1Hzou76VdXrR1mTGan}J5H;M1pk}6nwSFyu3oMOnd`Rl6_acr|*(V-2LfSwfYMx9T#J)w- zN#~dxbMYG)24UI?Yc!Wxd<@z1o{Ue0ciTo46|zf6aG}DBK~w9JjAc zXrv|dZRSK&WCCXTR_X2hiY_x>GVH=>nPr7Baf~Z}-_v_uw>H0uVqvqQkKjGGM5<`d+MGnayB6K1JP2D8nc+y=oco@uzK8Jldgww2#_rS z+Sv5qvIGe;!srgzHK{mvd+@S4WENlk11JL$yne9{Y);4($rD6zSG#O!AnQsHrkxH0 znT20(P>)nM8G&4^qs3}CuZ%PMzVENVvX4iu_fWvf%hv}-e*! zPP&56bFWb&=i(_jBpPk(Xp}q9(8MwNkO^DNUO_ zXKE(M^)u*Al<#jtU%!5JSHU`1tI_&Lh5hK0TTNrHev?1cl3HIUhQEv|GDY%KG~r*QypE=^8`*f9MV8Jr+KXS)lOYRKvH!?kW$z^+YfX1#p*GAnfK zz&ETIzYC>iZF@S}S+p;45{w#hPNs_jmE1eq$SY_WQ#+iyAD@D|4d7g!eV&RJBC%&L zj~wH>`r0q=1x>-K%hvH`Y(wXK?U@eC?~-|Qi8>}a*tp%>ugd1>*7EWP#i;xfp~Uc3 zLSG9n`>tecM}_G}jrv*pR~or1U-!D9V-wzAZlTQkl|SsUc_%?Pd`>%MVDtC%ZF~lj z>KP({z}`W%QAmsZvoZQAmW$mq{an*RywK*mu&UwqFy&22ECLy{*f)cPcb6oGNfk`~ z;RH7c=z=>mU($V0M#3kt{k1#>jc&s$Y^h#xdt^KK?G|tCEesg961vbbITdM9Q1J>Kk3Jf44y-{PKAoaK|%`q5!ammx8<}^Yg z%4hC(-H&Z>dWXAlXjGb#Px;g0npmgX0 zI-T0tA%aSifI_2-fX~98YX>2SiV>)bdPuvY zcww;nED`$)!LT=;Z?vS|iB?=QS%6)dY#cK{0{;C4=;B1@D8PgTY}GRyZ$1Ir%9l=w z1v04hK$v6wA|XxP2SEOBb(=uts_WZlpnZ&QGA}h*+FA*(sq1b=Sq+1K`Ryr^u7bV7 zs=zwnejy2M@ARV_KgBypZIA&QVur1%XuHCDWh?p?BdJZP)B9|6gmv3N4TVGBrf#y4 zavLOWvFvSCmzZq1HJ)QIS4ZtBEjK%K0|BH5v+BTRP6;V~R}4%MPRhsde6XKxP3^p@ z({pv&oe=|-ck#}464*%E$RJmuH&6I8sPG2RSOe8PXo4_FE@=lK5!ZqJt+ZGd2*)pG z`}NXAhes&)t~(+}D{b+vJjM@~$Us?yEoi1MP&k%-{IkeyQ6p^QsPZlN-N7hpf(ZeS z&+j4n6&1iTux2%MzzPjl(swrm(-}+_GC0ZI&8sYX_1bjgLHpbLvGLt$^8LSvDVo?b z$UlPQmp_TQIMoIQ$N>3w#OBJ#&F1rGs0O^<(bQnsMjOKC5-n8lZzM z%S$RoFEQu$sCNjYlDwGZ%hO?w^2OR}Ks?n|7=34+CTU46yS#*aa4gM{s($F(8@IvI z=)q7LO3LCntL$L`%x$D#;m-E^I%Y@u4(nN_O20#?kApNRm9B5y-eZ~J-p}$IK(EoU zYfqi#rGacl& z`Yopqm@NYuZx=|f9dyAmna75B&2BaR`Ws!yWk1lrqA}VCU+Qv=--YEgj%DuDWATl& z@OJtqWqKL5!V+lw08B3NK%$S+)J*0Eq%jfs~{l3@tk6+ihPS?54 zIbvR~=l#6z$NgCT*lUh*?3okss>}7zBD`dRPPDx?pk{2)x1TOf)bs4?a(UP%ek$V{ zmJxEgYfyRr9M6EbXGxYdTfIhR7wT-S&s>cIpH0N@ob@F!Iae2mNg1yi69<7Z*C5$ixEEXkGo;6W3&` zj~|1V$aZ|P;A~;7LO60KcUMgxYyX!x6cx@?xQ{W5f%Bt#xDI8$aGu|OjI-w=)Px$! zi`)~-W*V9vU*~LC6hyT?_PG{o*?@gvt>ZWnqkvnkhH`S#3X~C8+|Bg4$^%Bx3fJ%( z!N5p$J%D_B+TUZ&KbllM(Nw)R^8iCUSMowzgFR82D`n<59vfYVMSKBg-jft;^@Ebg* zzGlBW$cMT%QsL7@(bd(J(l@8C5;ti5Oz^bVE>Gtj}l(T0N4kY4+40smCFPDL4 zLGM-KyErn5962~DZ&mSp+&$Acj*UY^y3p0hwk!8Ov*kjOpXsTzpp}_^G-2Trs+uGS z6V`P_fZxu8pfZt6ou9YFENQl3r}}aIS>8%LswXyI83rkKBf#D>+m;(}w`!L!-Ywg} z{PNL-x!l(GJ&>5ea^_TL3&5DU(zt!J=-hpX&Ddl2BM7W-J4A4d$!VdI2H@IHnk!g2 zO-Ov2&uk4h%`z@NDj?;(#q_QcHeALq)}*~Y-(_FIbXEwk={R^5D#pgce7`P9x5Eyz-e>*fmn*!b5jyua|+Z2A=h4m|9_)hmGc+;gKp;schU$}-FMzjuQ(8_FF zKPTN)iatBA=dM&x1==ht3hc!MGk$})FO1J$A-}{7y9u;4gIX6lLE!XmC%Y}&nQ*iI zGaf_Tn{R~IYKvBkc_&S`>Ae{n#BxubREE!74Q~b5x~3{j1vVR^k|+RD3+;vm_HnC_5sh}aW?0_E`RuvBW|}Q#J?GF!`ciMDrwG)bE7vi*zqBQhq($#l zM4CnEYH*n%{V=mhjs-&@&MHX$K&*sfEB)_$5 zqbUH#)RNZ&twVNo-#(xl6MQ4~ou55A%u}bs- zKCEONm*d643PeKa(*b6w7QNVW+N^YPx~B~9>e%Lb(U!8bDJiHq%I=cJAl@+a*%oC=@MlC&O|X2t%iBC;kE|3b7O6W`o$f_uXa@C+7s&{ z)R>8hiCI1^kH(LRfH)_ms_#S5=>yddHobxF)vW(5du3JB7^9q7Ro0T>lHgr*)ZgJ* z+126tAn+k+G{C7f)@&B2WMq)%K9$4cj&u^#=IeubJ3Dd6<@UMsck zYK}1}EQ5%TQz8Fh`c|`VhHtzmRO5PQi` zu!&VQR8=D_+abOm_3-y#~H6YZ))whK)kp&7#($Y9JZhmqgbOC8Cf^|YF8f3N^WRRe~zjMdeSe-i2Wt&rnv=H1x z%*CJl3It;Lf|pl&R0Rf~oH99R5bAE589bieev1a(BgpckOy4dq$#2jW6%uN`;IK%# z>!?RGjX!+QDk@t^>%6M%uGz#J8eZT3ROxX%-!~I_EVNIH59PfPJ1ZAW0}bAwg1vZO zLXqdRb>LTra8|j3u5erZD5@)ZSm{$d#z+4s@S;1(u)A(m`P}~+-hqvgtevIa^DPFM z4f*3lOINPI=XZZxP9q^NOsVqhV{8MGbnnZP^;(+d6U?3n+}%=_ezB8X;j^!9^^Os$ zuE*@1J_lWGV@4NqjG_QQPlY=XF`x3H?rVNe71o|ecFY|@y-`tcI9$D+Ui^U7#->{& zTk?5-ijYQ(Kgc&S)tt1zyTfoeA-w0*&x`c#P+DcSSX1ntIM_2RL03>jZgulWwPDeS z4;?GJ z#ri;8?OLzF<(7W;$k(OJ+@_n-Akm<7*%oY#CoBYafnwV*x&+H2~ zeRH~LL#`Q!V*C>Xx}&>w^tXedL)*D?fiywcrWv9%9Z<;1;;YC%niyr=QHsbOuj*06 zbYInyT2Wq-N+s(Q-!6prtQ{+F{!4d|!Z-Fc84jguxi zJLvQx&VyIGOWf4$RQIzfWVBGC>9YfGpQL4G8e9vg!%nnw!$G(#N^s>P8C_+@o4MNG zlZd|Zf%?k`ipu=0L;Uddzrfe!IVDbwH8bk*(&{WZoHKo=Hnfu8>L2(?6=^pI|Cm9iBn_HS=bpPGzK-V$kyd=0Ux= z@XZ>%=cF6*n<{7oSC1GVPEAMAie?tWCTY%=gQ0;zS_5G7r(}0cURu0kuH%oZ{m3xF z+j~K=Q(+IxJw~_)k=QE1-U~netS7lu<+{1*J(A&#o;W%ZY!QCL&Z!j~;P|WAm0)h5 zk~bT6SmThJ*VZd6@K`vh4)E_)U7P(qo)_P@q#H%Yo|*4DGq2mNV3<2SC<#Q3+Vc{qMv)@-uJOsE~Tj_4o8FrW;|2HhDlX zQ_GuK_^n>;kS=?{!e(j$=#GiDVfGE--h2agnu^tBF=X=DTf5&h0)(bjWsf8Ic)4Gavp86VTh@+}!dr`24c_*fq$e%<7KvlhOJyQ<9E zr!mIkj-EPaBRO&>-x-MB@%<;-K=)M@DJ%b8uCx<%Lzzya+63f7%<*lqZfhf z-*FrX^4*#!6k8gzO0o)jv7=R72HGAMGn*@OqyDk7B0S|5!HqRpc(BC`hmS1Ra{6~* ztK>H8&AywxsUz}(xklK6@Q?3(zV?NBBDa4ma@Fz0=-|G4b6&N(-8D9&_sf`xPTZ8d z+#YGmYM)mZpO~`;h9fx!+WTnZ#eOuo-Kzv1sCj@nGcNM48!)=zAn_mbR= z^Z*U%dAzX9+@>fA?B8#kk7e-&$NVjhtDJpyz0f6rMFQb^c7g!O-;8$4vMYHKEQ;qW zufX^6K7s%2+f8xIM!?#&wQ z;1<>^ZlV`i<9i{5)dX2IU#R9nS z#3QIj+&@pAc=Y5F)^haM)g#P)AjR#K{$Zjy#fqdkA{`u~G_ABpp4pygnV8p~fH9b3 z`2Hk^GcLSqeeh21H91j^LCxIGn^KC@FXBJH)oKDcQCz+>sJW?Txz~+gRGo-A;6Ek7 z16H9Fe$ZJO-_%Li-l}Ne=UgqOVu8MQJ~94frx2U(j8MIgje6c$q5m+)2*iWQ^$ak6Hp`<-97i)6^Y_) zmjznYgiL;jAWr?1If~x!`G`%#1MPK%f46eX>o@2sv|oacK=(xKp?y}NlM?XVTr*E1^mxl0?ZGIbK~r=dHK#+E1^IWk7*zv)7cC6p@RA|0z2;1KuKgY5$7M$A?1T z1qjC=69j0Zk|j`5jT8ON#=r)K|B8mZ-4A!(@a>UrEUxS-ekv=jZToQm-=A;((o&0Z zp^WMR-ex^aNwzy9c*VtC!;UstfyG^3iuUNBYpbEF36gOLH3QC)%IYlh$D^`nznf^h zhLd^IXjvA`s&WG~U}T00w9yVks!O?j!$>2pu;A(F%(<$?JayO0D!nWK&GOI9G45^T z^C<#m5^qUmnw^qjA~@HxY}a#rbEN3(wPyc4V@gU*qyMoo-Ix)5P4_-k&Fm z>uhlRD!nz@ZgH?M2Ga-B=H85_MJ!XV+VwZl#uq~IuqMr~q3s;(ODdf4>0$cJzM*m( zuK&e9eBlPWY`?Is?mk48cBAlCELLvR8_P>R{e313`#dwVZrhdX*S~*t6?amK(e|Uk ztYDgN1k5$C>61N?!X_bjjJE|x<}4iRh*KAoY|%YzU{u0T$_Q4 z`6f*|EM9O20%&hGGH-xicD@nVgfg(KvJUrbR`XTdL60$DUAkz}CxCJ&zuY8+9|5nD zHlT#<_??x~gOTU6!Y9aowiTPpEbLEM$B`U7Pnzz%LZdTic{$`fYfUoulUubVbqGM= zA3xqQm@eL0@cJBtO&2LRwmeHl(_`Ym6r&%9#f??~OzyI%*T7no#EyxS z4Ye4lIk~VA{*2=pCJE;k2ixA#(n2-rUw3(S4E3-@j&)vp)keE&u90)@4u&E7<`zqC zwae??R4A1gA&~})?@=T+_N?yUV&+Mf;&EI3C5O7LJbMLCBVGEcvS^L{Ks0h228oinj?l^F7+Qbr=MCJj4Td% zc_Fd?+PDOP&H_W%){>JGgUVDN&Pwv)JOO=dHm$Tj*`Dv>JHbkZ*VvPTuD3j1YCq>T zLE97P^#M7^bX=xG1-Y1HBEicZDF!wEj}AwfOvd^;~krdKaIxR zQd;0YGqm(5ht-A0XoHg`559o)eiU3{Fhc9fus}K?fnaR#B8$mL%(e5qH9OB=I-y~N zZMn(BtnUDWmtv5{k_hy&a4g+^fuDrxEeZ<)a}Mymo}R1fqoKp`RG(R(1$9%%R5-!= zmlPT3g_^$7%sxd`daCw&7)4s`5qxaJ^c96^O~|>slkv?Tt8Nj3IMt(^BgCVk1)|=z z8$L63sOc92TiZIyuXdZo#XYsBZkRfp6{c@Ir^}!aS#BgkcK$aI?qPaLUq3i!{$!zQ zG%13mq=jRX1i@tThG5l%eE|*JG}|dsOg>tn{8EqSaQ&Q}`sg%jfZ|Xbi0Y;8;)@yA zEz4qfgCD5hNKCNhdNw!#`pbs(e!D~bBAYDxiNqbJfzoysh`aj+*MS*%=p^l|V0_R4 z(*9k1A9A|2{3*+f)S6S2ox*>rY6$-J*YxrB>Hzy8fAIBI)$`oC3Cu0JnnAMzzf>qk zbjE1EKO%p%?xHBzPlvHQ=CFk?dc>2iWiL3y(xUv9=c!aF6fEwHN>5~K*O_Kon`*dg zc^wi}eR(g8#Rha=s#YZ)>J<;gViEQHahswJ);n}Piw>h*A4u?z*x0Rpv9Q*ats`(# zUy6J+aMEx+1x)YLyVh<+(HqpViMd8~{EpK2Z&L4={%V)HdR)BoD;mR0>lQM<)tL_T z5GfLq1(Q{{&*#!>#q%pfkuhZ1R&pHc;fHIbhy}If^QSS0Y+b}`8j4@$VFEm^rvlxE z$u@<(e@`YvW*-aG(rv@A(s|Xb^Oyov@4Mv;jG7Ww8s_xDq%Uk06qK(Ma>EttwY8bv zoNN{yRJ=zN;l#GANwpWCaF`*Cd2^uZ@JBt$}kYS(t z6>7l!%BhDUDt>)c-sTiq!;RUzykZ3KSYi5WdGWwW#udl5=;PnYz#;;)ChG`8o|gNqR1~OU-SgAQSTS>Y z>vnO+@N=f7c-(Ts#z(g2JNYo*_mq8|y#U=P2S>uYjkQ}5Q#VE{6)Hf{yaZt;W7{t2xU?yQ2u)QU7r;*V0KD^ zLHz6t)~4f(hhH8KT|lMYp`D7GnDq4Z%d6<^KkKfEIV`qJqSCFY)ZAsS?sHK%%}|;% zrB&^;3UgrV(8hO+!86;X!Xx=5Ge0k@kc17?87NfUq%WwH(-9}|o!woXt z$uE_4*Lp&0;yGQSm%TmF_mF61K^Ei2j5E^Xc0uQ4+%aQ=ce&kjJ%Kcxll`5H7KTXa z3{VU#3n%)c!8TmA`l0iRJmMk%x7$umKaTG#E;vn{`Kt?KQE6UQWwY%y5|lcJ-c~TY zHjiIvgGv2E$7oAa%~7m<`%N9UJ*e|pNlvWfHn>-WAvk0;$Rsb!cs*!_0!+9m>1)N) z*o3vsU7-||@Xol-e|{cH1hDGRZ;ulKmfJ}_32W1by_l!dF3wSUputHU|Kp4l2$NY= zb{~pdtEfcfX&cY>%J*U-I_&YeR_V0{*BnSuJoW=*&wiY5<~x>`$w2%7!D&SNVfDd~ zwm56IiNdz2>ILmn;X6l^<&)atd(>uNy$u3^ZRb1?(+c@M#Byt77Zyu*GBpiDOBYXq zdDkaVPiOZ@)7J;X%XoNs18j163zC>rBKZ0)CC%{Ey?gVfn%z!>G7hRQ@>vm?i`?KV zdg-n^ea289h#fl;HvRhD^AV}9R_SJKdoC(2Rg){g=|syiINs&kOJyj6Yux-`26+d_ zf%JA*JzFNuw*v8!%B^tr>Vd#7@#=Fxh;pnj5caLS^kEOTR@)t_%wThGwJ&UosH_v} z^@rWC!1&jYSdK+Sf+`f*kVun{gx4cm_)Zrev+D@(UbhF49aG|UvIM3wH5 z4`kJB%blQK$Qx?DO6##J$Q~ujgRs=e=Wer-KEFF-suDw7R>qyiS=$)dHE3nKp#A6{ zniPaiCP@qOJeC$D{B(oSaP@gTQtE%u*Krr>p-$GcC262tNiv5Yl@R^{i`^MQO5Rc zUFXKf@(nUkVVARVOBJ$v`emDFT2qJT8R4!!4}-zbz)rtIl7a-ubp#tik+QBfzsDOE zbDA%LW!J?#{uw5!J-s`E4<_TVJ*N_9=fms27wl&KwXr`AJk0hTo$VTY9Hxczz!tUZ zUMO)$8C8d3WM4q=?fygMbhEZU14glVzihZkj961Qy3M=^GeN zdlLmnPGGR*4$rq5+jJxb^^&Lk^FM1C;<7)xhOIT>i0fNrhJp{#Ld*>*gCF&79g+9N zZiP7_EGI1DBKCMM^K1@ZOWhyH`g<9}F!?XmCgQX}Sc196n$uXn5HF^j{>&FS@wn0Mpex`2jSM?nj=?pF5lH znr=_5+*XM!EQ>>Kl(~XkE`y8K&86C?i#~|!C4KGh%q2`NjuU47Qi2yfL*4aQpHu%e zCJl&43cXAp9X|v}c?Ai4P-{iFq<%&R?u+RnZCIE~vJ}1nHN^n_jLlOL|cgVy>UkQcjeotTsvY4P0RT&^D~@I&#Qze|9qD&(s`3 z5-&)z?G?~kLlQx?7GLvapM)2Mh>1Qn~8(zk2zn>J{I#hE@q!`Z)no5 z;$L9)M$X0TC|B^C_C+>>C-2kY2D}MVIR-YG0Ym{(_D24uCawlE3y{{{!3?|ebz6#C zd!5dS2OGj{a%vqC^K^8b#O?f27-U`ia+m1M5qr^llO%Zo{%G;pxM9Nyd$={c6%cM? zW^jm{+g!*0`s>fc3v#zy7?1RUAoJ8mRWqG1N(j*1k^NgIQ^ipd^|A)8#f{wKBDnbl+dQLz^Xy;*6P2yRxOQ{wfaN+EPX;;rQwJuYH zYzz0-snV6clW*7IKXW9z3N@+{$DC$-jQo20aF%`#^6yt(Q|?VkyoBbKOVc*pFZ8?V zet?m7^6LFDrJszfu0G~yqa z6DHNuz&AskY-g=W$~|TCWUBF>$M#3-(N3!$d!%-4anhyiwE}`Mzogb%(zmVAJs41d z?-M)+&QRv(pUec0%mgSdS32oX3( z*7<${qhJ%o`{Y}G?~_MY_ktWNqou_?$jgcbd%vY;Q+acvm)&#g&bB`Kw_Em!mRVm^b76ypIz^dab@4??}F{s>KECD zlv?Pf_&}q*f&}n=jvg5$p)*##2FI!!S#o#9UTH{S!-3uT)%=q1A6H_I8ugSM{7Da0 zyl02p&W&`Zlm$VX|(JG>;DY|6B%r7^C?+j~ny+ z;|shaf97gv;`&^a<$|tGT8oMNZ`0KcX`uFSnC*vWV%?_9|En#a@dx<8Up4dYYV*Re z(u_9qLc$v4f=PXZosaPeX(0+>G@EY}HhM@nolY@7KHHVO7RS>lBv9X9vCr~3CPD&MV)8!Y~hzmJ8<=ws-#V@pmnOiczGROQU_&Z zAO#$Vl@8h|?2LvbdPV~TfgHn#LDZB~Ao4xRaZZHoSnCl>6s1;{`Vl`xnSY9 zD2J%6F_?YrNHgax&xBFJG5MOXM&iU&7h@LftOc6BTlG#Z38T{OfAK#GFVc^uKD*CyLjRfqU8Y@*`{0 zWtMg~M0>t=^9Iwp#GaxL%$iT+#Mjd`^w^FQY(s{c(L~=9A>R#7jx9ZY|F>P?@QKW- zGo0QOek$#i6ERlkW|Z2HH6GaB{s>$wxh&3yl-`GZQD~v)7M+~%3*_6ab9)HpH<#E2 z1>Vm_0Qey)@3EfBkAsu_s}Cnd-4SJScAIAJR>(m;_@eV%sOL`5hU>~cJcY~7q`erS-U8uakEsew(3uzKt z-8PKjc_t;B+jXBk!dC4@knbO6%)>ILw|)Hl^!c=LGR?kW1G}HPHEQRjnnlOfXGFgF zt|B4HM=(s56?}4Bvu-nf0|RY1d}2REf->;=DXWVMX>bjFuhs7b@CDSLN4~r^FB{0H zNP(y%;08Q9qf_G>5wuH$_Gw03nQ#gjMbi9nILm8zM`?#(k#;5G7m|XXrt&Hc<#w#k zZvNsn+;z5=;(*8V%BEHz8mgx>C((mr9p5)?V0b4dWK__&bSr+_E8_r$6IIw$Sn8{bOUqiiGw(oLmf*yJgp z62+^0hztigdffVa=L39*Zw}@R|Dj_9VtEbY(`qpwE8m5f*dlFJ!EMyeUJZFd^xDu3 zj%jX>q++p8%&~y7eaF;7G=#0;H|c#g$EK4Au=z?7t`NhAPaSPc;_Y@*mC5PS?G*Dc z5z^*P^=lHeZ&2QFxpY+4uA@UqgUi-H_=OZ*P#2fD?L*S0k2R?z)L^G=pbx3;WOd>l z{;W);kL^UOyFbyFf>$h|}11kvB_UZHTZF*u5D z&}jjdfvqN2gNQw0d*Y@|y?#ecI;)4yaewBx>LHzC?U5b;8;0?lrG59PBD;1upA~35 zJw{@OLPoWia_&ZIidfd%D&N=k&nku@9Nwe)&nlMlGO9eh=I!^T4SO3Rwly>rSy}}Y zx`F`^d&P=S2q&M6ljRFZxYOLn{;;<6Fusk}bM+x`vlath(={V% zy_k7h-vs~+&eLJXZMi3uqyn)iQr7PJ!t2e%C-ECpZpxE-P8IY=kA8`1yPlmG^Ofml zW^p;|pJh@*IqP!r_ZdAvg}eOG_h8j|=V>9sMWQ^3Q}}^}tSY0p3le5K$})q@BIC^# z+jM+0fU*F0gad`*LI~8q9QdVEG0@ zMKw>z4t&0d9-bD9*Y@*yw{v`}TZ{U|F7VCS6I^QWDeqo|{;}zp=ImrA#6!VE%P#y~ zOz4D)ME@U$fi(@Yu0!f@qkfh}gxw3~$W_A-X~-IDBT&fX^h7EMUo4hIu8!V6!LJ(&ccma~5k(m-}~1Kv=P2bhN;T zunl2KnNYmB+iAZ1RswUpq#54JP^I&#kWA`x0tIhI$+#Aze3mfa`>r(*Zq$!B0t~yZ zWbUp%%dYROkZ@D&G+A-&74x(xuz`TuhN~oPUBt;;r}7I=h^AQvTQd@A*9!PD4SY8X zFP$61(S`~%eU0yTb`51^YM1`&z;hcZ=`VXG&*5AJL|q3$dUFY}M|~hwFF3X%2yZ$z zEkPLdUygws=Ixq%DXZ138Mb_d`c`Bsr;_iFj}_bBgH~Ru#3-JAS|amFr(e~zKJPm%o@lw0l2A#wW`r`J>OKIFzvq4zX8Y_e?6$l;FdN_Hd$}=`J&2r z$;-}ovoSnFukp|&^gX6lv&kulM3Jz%8^K%A32%RXZ4uPgj<=ogqln(qqwsgDr}$;t zK!J`_KuPIW8G&74FSt^u2~?MYRu~k@aK$ zzbJCe)ewiO2SLi~p~IWZCQdi3j&=AG*RUEg`;`gRck_RmD<%kAD4Q)Vrb?jiE!P&a zJr>^7cQVVuznc1o{E;IV$LyMD`NN9b)25qcXd<)hn1X0acA9#7sSOz?dukSKoL_y( zuawgMTyq0sPT(VzH&FTxv>^u%y48@*H@#~YKWowdr}-T3uaqt9Lg(O*=XGMWM^8>4 zfg;?HRra5=!b^X)<>|JA>r!k$IA*ns@MlB!FZ`v05}x9GuY+?8uhVm*W<3D1f!7o! z*DWSdyqUC9q8bhMcli{VhvY9YvU*RpRLn|R(bQip8SH&(6vl1{A8E@9E1^=Vt_8K7 zi|M^8)v*5!d$de(E3=7s@z{Z-z@4?OXR zg_69-2CbO78F4;p?k^NVS*G=v!con2A$};JBAl|QUal#_1&QAuCXI#}Z&pFvd~Nhe z?cV&S)SW*jIg4MoQnc$VJxrdVZ<*8S!#*8HeIIFi=C&adw$o0%?KIbK7>Nxs3mYe) z(f3rr#W*db6c+?hVKQl5$G|Lt%{7t`*_CU_b)7STx72AssB#SpSjnZ&s@vE8qZ6!9 zG!L5~ouAr1Oc5tN4gx#M3EFj^`H}F)@p_9{DH@DogGZr)Kjx!R!}YpDhU;TiC%NxI z{?|V|6qGjtI|$;-kL}oR^;|pT&l5_tZ(($>d@0&NL+mE-C3vzi2G@_DGw=sGRG12h z-2n!K{ShlKvP($lz)V8qBrJb{NBxfIAFgF4eJ9_-Z2#mgO?H(Gc!f_qX=CB%brUeO zclfTJuH<rb|KxzoYGMVe=e#Qi}6d?6x;D;}G zLu=QhK1)di5}3~h9S(aLTT8!xPMZ(MBqsDV1WSNwYm6E2yH}WShnntj`8AukZ+uKu zDDIbTNx>5I?roExcrA^5S!J$&bs#&rxmR?^pCW<3d2E9NkO?V8vhurj?mQk{Oxa)3 z5BTZ3*zkNERDZIVXGsV~Ct0Mc>o1t{jc;`SpOwiY|6?!M_;0;n_j5#n)z4l~g53)S zzaVz^8;*V3dBdV$e0o}KCP%qm=JxE91m1^K2+Ca+~AxrW4=oZ*t$?ra|$~ChQ0*@ z;v|h@5dKU?VHmYDRQod)OeU=l!yK4JQ~LN^=P*&&38nMeu}!M&AyYKWk1>zG;E)+m z$dxixv^fPmz`Z3duR9DkB~hZuV}&-f>d3c>Q&2qnG8tGdWftI>w*9mVwpdqOUSc|t zO#v+Ex2gZMLD!n^Rj2>;_MFpqo<__a8-bYkE)pu=((%&!8Wu^L#a}q>xrU$we6V4M zDcl$4WXwYU^KDv!=W`}ZBtmir%K(^|7&;8ka_;E>p%5vR31_`nbVyCv2D8K3S zjB$Qo<7HYy7EzNfW`&ikiKc89C8wKjZ9E#=?pD*8uVt?X%@3c3M4rT(a{MgE>p;rf;^PzQ*An>&hBPwowI@a*J z9l@;H?_wBf7a8z|W6`=FL+&RShx(9g$#c)|O3XgL`(+hnTh!Hged)u)sC0723#YS# zBx|)WliG@wf@4&21SI*?3q3s)g(yyEJxjqj6U&19EGj#mw9JY3nI8L5p!x${{bD%{ z*Q$U+{jw8;!HDF5l|TgV$IG`>4cAW!bL#m*V#K7RoXZpQ z3trGVt8uDJSPo@z{>OA3_+O^$CvTfJL@U}{d)U?mVe+dm?p-iMO{87dd!&4+&GunM z)Y|H1lT!@$xCl>@i&>GJVc~>aL;GnV&CJLqj^IfN!r-sv3a`p%-*gIdPQF-zWUs>B zeVF|CmkDs*z-CV-O(M;pdyX(Xfae-6wJVs|qBvQdUQ_(vMr=~vgtOTbM15Aso-3YP zNi%x7;ZElLi9U=P^%d-x@@0scc`sE-w^w%T{2IT%U4Sk+dsQkSyAZ3uUoNzMKrYt@vc2s9(gWe{e$ebpI!J zqmRD?u?gq}&@jHg?}u#nqf1=s$E|S*HU;BA{BFDj-m&4Nq~;I(x9K6hc^SyT2~GsK8QWF_(W@rQ;YMGP|wkdplZgl zyk6Q|&6#ewj3OzYzD` zT)+6SBnX?K>C#cX?|jKO{17(iqPH8HwTUpvw#GrkRaB2<@nz$RJOdARc~9P{+kwADn&kE+44?IxFk@Vy!UnEs+vDvY|6k#lL2EcBA3OvwFUFfM zDeG!-$$5zBu+C=upVeDy`h*;%_auAH4~zQ#1&(2Ql3AGMes=DNdz#JL3F5)t(^*ds z?st^)y==rfs0%y1o_E?LOQ-s=0V2bn=3-KGlvJ79ho@XUOw4=$B8^CBU_bm%4Q#{T z4Xn5(cWQ6~FKzCKrm;IkAdo$^k6j8ooKv}}VM<~b+wXXE-@gv}W2FA%8eeiTTjk=) z$wn|AgZdb6dRFd7%->{6-L^;e*tWM%c}G$VcFE@?gLu2OHF-(ye0 zrf!6Pg%s|4&D+kVBlMG+%9gLMU#yUl6bWhMxEiskTbchM^@}b@D9`rEq?LY$E!xzU zn>yR{LQ}(enlD4)vPYdieCW^<1vELp0mn`>QjxF<$geqym~w#3<}B$SxTXo(K=_eh ztLZ8`g9~IC-lTVeDoyu|!}gKROZ`AW_UG9vJa;*8tLEtEBFPU$#d0Xr#fe?U8tddr zVc_E)svwNiud_w(E-8Zx%i_I9++z97S`R8eJ0LhMBrs%yBVIE)2r2!fC!)H@;AP1| z6m2T!zx1?b_Mm%9oiNw8-(?O0%rM2B3RUndgCXjIyzq8~#F2xRDnp8Hdn!xHrz(O+n5V8H-$_ARGz?&LG4 zE(1)4ok&BJrkT#hTrVu%0URsMoSKk>*=C~o%2WCN*I{9vA;{Rdl}?*TDr+|3wiVFn z{UEA?uif#x>bY0q*j`-+PoavY+KN1@N>wZCmwz5@pmn;umAgwDt6a7Ig$201T_*6A;yYEIy~En7`c7Oo#m z!*W}qpV%WFT=Kk;FyQK*RWD3)77eUrJtUcK8$OxvI|=h3ynNHJpF}){RaD6vFr^;C z@GBAj%yx+D!gyQ~&{I#7E3lePycBkPza3+wG0wOueAj6)L%L`qR;#l>m9XRVkKI!Z z4sEnt>pNogAjv7?=#n2Ft4}rhqQDv!&=srV1Pd;Iewip)MzJsFy8uali9KHAf9$4i ziVVfJj@}Ng=dzj&F}UI>-OZ5C_vUtQ%4pNk#I{{B*ef6B)Te{kkO!Mgt9iKqXx1lV z%GlN1aJ8Cih|Ig%2i~@E4vYNPu6cD6r4ih`r?MidQg6cZZteKv@NB$|xJj7FE~S%& zoNNsoDtNT|5*rF9Mb{}qY2Zl@!pbm_U z!|3@~?TsTp@Ca^(Z4&9+asNbHGrZv#8;>Zze6-}pN-8&m(9z`0{Xg{2cJv9wzw7yl zcmMl(?yY|DFg@$~iwB|s+Wu401S~XlCy}KvjF-Hl zAs8ZhF2C6A{8?ucnR)NKo#zCsAjvvuW4B{YZqkA0MrK7vcZ>@W+)!*pANWU7Os%Y3 z+m~6OHiPIB3O9a(6+?pH>9VquLhl5q*GKZ?=XH}yT)}%8cPea~Yf2D6T`in&(Rf|- zR%`x#njS?Ug6@to0cfLy_`XRtt6YD(JB9yBKBjg>3*1#?AN;`J#}I&>Yw&?3r0uDr z7g^iM{~#AUJ=k5}u?FWdt>5zhPi?hC@4Z+gp!?2d7NGb*OvE3M6xl{qcO)1m9z0Mi zie#SKq$dmpkZB=jA{m=9Z2BL5GhJ_MGeD`-oj9mlos@XzWhH#)*Wv3&2w!gCx|6fd zHvZN>K?{u*-OfjD`yD`B5xZPV-(ah`ZqjJ-3t$!jMLPW51S@D8D6iA( z=LJ$@S6A>EhZ98Y4@JRKHcXz94r$~<6uJsQZ&*JmT`l z-&3>RHw~?}-s4q2TW?@tYxz?CdXlDnD(Z4(hokO)`mVhoEoQ>ooaW!r9h&v0MGR1o-8?_DnYRNDlsp2OX5=GY5EKi1ouHH8bZ2 z0Zdmf>auU)gNL%_Zj@d1vElJA*pvln9ee4AMW|R@&-bVc*ABiok)(~VO4RhsU(!XT zXq{<&@H{$Q|I?s&pQ}(2vU`Q5ARc!BdTxzhuBS))Na=dtns>QF4tbR)Z9XBVt}Bk& z*0sl@-j#HG!zJ97WX(sqBU_&kukN5PXPGQdTsxBD`)h8@;yC8AU+9_9+}Zul1#tYc zkHpG}%!M=FnW26d3SG~+Z?D@9%VQt)s<+dbaq=KKbM)Mc$&cAEyntBty|{w5L$b_p z`5`;V#6?(+C-v$IDM(822tU36M8Y*4rn~c#mg}@#uIB0~Mu{`WCa3@*1wL|9;HStJ;-8QR5Uvs7Crz0@gxvck31r*MgWI6gR-U{@{Pak)6 zW_|$zT5v*HGm@H}*#5`ZbO%|TYjsgKO-8Sh5dO8|t4rtL11p+Bj;ANs2Em%Fm_Y5a z2ingHWOCVS#1&0OEiRa^B2hf?v6bDvms0KS zF;$p!qcz~+y4zYVG2M(2>#>K?W8Z#a7~0g+UK2&!2VhI9J!M4SsEmE>QEHJ_&1d5 zvmi0_t1JxA(WburN6ptk1Sh{7-C6=nhj+d|krWrNwH4k(zfZz;lF=G+Aa*}zUj5H# ztvyZlJkU2PYzC1|Fgx%9^-6CblGppcTuf1JGoak%W0N-S|ntWr$q6U z@;i38r4z*GcJee!WhW!nr8t28zA(Xm_>s~TZqxMvQ=5O6&g1ir(*5^4V8?&C13Vrk z_{rPU#M8b|3N)-sZT|eoB(S;2X|8W!C{&5q0 z{g0a{-E+L%et+<-{sqB^b_;N#}s!}k!|*X zWe?u(PVo1+)p9)_qXR9$4TGy}IOoT8zz31`?CZc4t^?nHzYZQuiV>>C+2}QN;ZtwF zw`Bd{%y(kq#BrZPE&PQ^BMoAnZh&>0QwqnAPB5oC3-{z`4+*uEUhBP5KOr#>8B^Oo zddwR#1r$7}wZIZEXpcTPB3N7AH1-pTnf96>XR;WztD}JZ|8^9}{xJ$%4$?k9;c3dC z@kjWLgUiCQ4yGS~?gLcDUg~rZKpbj$EnF$Ry05Ra?-$rpg+6&x?DH+Soi8vTMbkK> zbHSiDNc?vy1c%g%iHZ1zgX)$2=;2Y%G?z{9+2b=1E$L)yAdc9Q- zg-^-j`rO5a#c%y?;gKrio4!=Z>ry_vy{(?DV;?Se9gRi03D(>0O)&8}cg0_eIe-X~ zpr<9ccbtPyic8-)HA`Rv$|t*0acHImw?6;%8t%Bea&_FmC{KJrsF6}RwN({W-h*9Na! zBWjCFq$}rl5?P&3@~%<3w&K1gx}v^~#yXl|`rqNoUR`e7Dex|7u`5mNtJmNoDg948 zok#vxX@4D5h1<6O!b&$tcZjrHbtnhb0iPp{no8hJvGJbFi}v?gGVt>VF?-kNVqRrI z4dZ91X><=|1^@q5YE$2%atUN=2RYyTP~0s+yV`F0TO~Sr|9`85&%dk01J?Xl^ZgMd zHyPTn+#v7%GZgTjv4OKF<0V;nb

_|B-XJjq2q&dgl11{*O{kW;AQ|o4DxrQ;GSt z%%mJ_<%dtyB)WeYdHeDm2)}9(-O8)uwPe74QUlm=3z^Tg){F?mW32_j8SzkJufb0W zk>9-PLox(w_^J!{z?%{HtiK{_nG#A_>(1fGzvZz?kF0{#Q~Bh!!s%Yya83bUS9yN$ zo3@Jae@WMv>2DgoNd;5emX?F-I#@ssqL>t0YEJ&6Tg$jSYpzM`D)d7G4q?a?rzjv& zG);Z~m#Tv&@9)BrzhpDy{5GWb<9{zKkpa|}+An+huciaNHSXW@b#lWgKv?;HjShbv z+MTNc1#3*$1>StW%cYjuKP^J?u;1Mk+h0Xn<-cq<|7?{;cLtBxCSgL>pj^!Ve<>I4 zl2xLX=GOkVGNw(#|JHsyy1Ul=m-Yjr+{^@MKg1B}`tZRZ2uwLNU-Z1s#*-x5__YtV z@Ou)lg-h=lIYs)Giu15>qo_n1GneNPAgJ^pUFs>I54~D@96vSVq&Fprq z{4)#SY&~FS$`jQ$t7v);gbY^#>895h?d4HoZ?F89&yFGwX@otPujVEvlW!^iGKt}U z42g`Ln)h&PGx6!YAApI!0{_CKB!K4r1oYVwKPkmw5Bne*sDAKJC-2(UF9}9Jx6)C) zM$K;MHdAQ|ck`_>UcNu~UUKQ-gk{aPAL#+@i8$c*wa8Oj`2TE}y@ye(G*6^#BhvUd zpF$a$QqLkc%iK*WXnOu42qj*PBcdetl%63xM)wCH!IkhMf49E*n zSb@sQX_^3EJJH>%?8Voo&%_VyNCqV)e=DBLCi429F3O(PJ>(n*Xw)h#GlEzIyX^ta zU&E)R;_$i1--<^c?)*NABMhoQ!TakpIRXI32jFQi4DYfv9vlMH#sy$hm&J9QM2xW; zoa9Fim3+J?0{&D2`Md7MwwHB)S#~4ATNSXdu)GK}T4-8<3k09JwKMuA-rpauJogXU z{ajmL>o#K;XL^6Ck}SjFOFAh4nd%omFDMZJ&iQSUw*0|b2`JIant)3H5((Py*-~oX zVh^qi=KQz<`!*^(X~v0Zb~7)q3<&Ftm=6;EzY)yzT<>nWP%+BPV_qY$8fD=TYHiTB z5wZ{}m)}1LsNbrXe)=@cEf66zTKdl)eWQX1iKo+rvojNwv)Wo=c)n!I&Rm@|y0rIq zBu>7h^sox=oGQVpg9e)y?xV|0Om6}uu1@AgGTqOYdHk)%Mx1AiR&JKPQE^l~0-=w5 zWlHp=HF)0)>>JO(b*Q|K>PCec;OKU0Z z-P;BJCc|$f1vEK<=W`+GbgJj-BJ38Zp3A-p7Y#bCQn>|I!)a=tTC%DnO$yVHH%@^q zq4y&}|6_84p0F*p3j)5kzceLepj4f{8WLiQ{UuhBc(F?wRZ4J#UI12ba35lcA%fvh z%{x4X3Lq5R^EK1!G_YD{&lM?n``c9x`C+M|S@1`b7}JApuT0SK?=Kouxr$di;Zvoy z2^u*lCB8c|bzi<{rt>J)UTTh`;|AUrXd{TtdPCe>b`xRTHN#m!sAI?^h;pSoovG$T zJk?D zjDx(Bq_Q(6G^&N*Ao;@fEBDcqBP$}TtgL)omVK-L{E2-0xMXv4(>xXvDzHxVeO60d z9r}pWl;FrycS8r&Bx<+lY|PoQrQzVSR7GSX_8U#I+_Dkt<1Z7!;+a#?sguk`x9FF~W`k42|Q;q1opAu0+*MN2=iIC+vX z53ib&onN0CnkzO$3UPyVH-;(qo$t<2;I_FoRr|YslAwNwZuVeAXUuM*x}qqiXF25y zvN9?tjeQk8ZGAl*RYzhi@d!Fm@yDkhy;6qC*-h}oJxkp1CLW~)Z+iX^A?S~innw9$ zUfwqxQ|zz$)dml#fVk`Y=BL2Qj{dg_O2toZ^2?t)p|y>Dc7mt%-s7J8iLXEJWpe$L znk4hr)H})s5FiX{PQ$vCW8#r9XA!r}u#-}Jhduqsnyl6@PD|GxKW>HSY+&NP$%OAG z*|PwX9n@yr)6CQqVn0oO{|%&pnl`?DLP=P@$Y!X87qhYx%@ebu}-Ru6ovmA`qs5@-nD!Y`277uYofryiY}fmAP3q&$cI04JLa%IG!Z1{gs*e#D|24 zs7oqOyq!rs;1*;c^(UVS3xj2{2h~#0jY)`q$hY(~r^$zD%Lq)4frkwmo6fGG)Ji5b zWdq_)cR>%^X?4ZPm?MZk*X=mL9pJ}=T%=sj2!FL2rff%Rx1YA3M+P-PoEiW`3FZm! zwuU)5(b$EV?E^)CF|IQr!1fC)kvBhoH0LH*ckA3|(#ZfbAA9{ffFXp>(`H9QDEX*_ z>&@C*WIq&sli_nuH^_mrOGx|c>tOV^H@VItjw^FHHKW*SBNriilC*sPfnEWuPl_t`bwfn6lO&d_wI2z)?8w7{Efgo)e5Y#?a3!Aiav&?P z06)>1S@3#Hzpk{?UBF_qS&!P9BpabhdT2-Rw4TYAjiqMSvp7za!*8%&<`?#%m4~y( zMwej^;+LyClFn6eqi#+!C=^iO0~L_}?;P(l*vF4@f`>x8#gVs@Ydtip-h|h9JKPvp+kHvFp+VvP zDP}$v@hx ztVMHQY)O1Hl^Q^5bbc7K$qVFoA5DQnFE#r_wF7X5q(nzY#aoh&KBrrogH6M7boxHM zPg^j&^2X;Hgh?hOjJrMMRApM%{LNf|-DuXaPaSkgr|13U!gHfvqWtOW*_tI>3DLBY zk=#4hqx!{qyR(50mIr42qP)*r(Tx-UI)2S_s(L}MX^9^Sg9B9sz{-8Q?wBth0pam6 z{>q*tvMUNlOj*3;6(6>@x4S#q{lFg#fuPW*^_bV2$tEGEz8eW0;lxXy(@iUq8s4CK z^IG=B-P-ggP$b;cX}<->1y@~xTxll1quY`n4LZVB$HNVcU|~;J`%}l?MM>f~j>d%P zqUBuPN3F1qhzNZwQcWv8arf=#2ih*7#kF}lMM~f5yjU)8Dqp6We+|cozka;~hgNRw z6juJZPL^4D!mO&iF^n??J^3yWlu+WE07NWBP&Hx2#B9Zuil6 zgoebOE)C$sb>&{&p1s=N0Bg20>0-7w8INabJouZ_p`V{;b#2n*9nGwg^X`>lVZ&LsnyBVuDf?5}{VyuA28NWG?F>3- z>q77g@l`zZka3i?Y^Nu$8}g48&Ay=LgxLRaal9s}FQ@aAtl)XOVyY$+wnY<&MPotT z9$SQ;CWkKcq&?}iVS%)C5;tz>mh(9Nn9%QoL@I)uP=13@zWYu+!{*gcOazwef>3k{ zGj8mJ*9tTrZ;mMLr}fQxT2P+9D-SpQfW2Y2Q|*D$Ec%@I&>2zLw3X}gOSTq_)$%?+ z)H_iZdmnQY?3Rr<&LNrFJ@7skv3U0KeMZ);U$jJbOUh~9)HU+cEk{hnS1vJWZ4^e% zmG2k8nBG%cma;QbxOvd5tIG;|frWbZo1{mli-I#na#dEekam;%Ckz&7L7o1wI7uLY zP4fj;SJ6`bXg-ZI=~Jixl^I(^tt5)=xJQwel9JLdH`7YV$n5MN(&Ed{A@Ms2lTAc@ z6jiQ|ky+!m3+}3q=m5Qrkeo{22Fm$-KBV5xeVK387~6zck9KKenC^0M?-MI0NE@qL z#XM)?V13FO(i|6V8Os}exYVAemF!(=GnSjCaiv}e%zUgg#!q!;iG;n{*7s{WLhc_6 z+!GQSBOKNT-eBsA^4fd2^(X36dmAG%6sOnKy|_N=^p^m-GnDa8 z3cYPk?=|5ot1Cl)`~0dnl(eMp)Qo)jTjr?H8GdSAE5zqSvfRhi>^Fs0?mipjS6jb)aP< z?UXy~p%uP~POYh!>zIY_6$ywfj&gcnlKB4kEG5k;f-ehKoH?fAI7{pXTW}XXYc|{Q z;8`(IW!V*a@rlo29$ZQp(84Rw=}fpkUz3(>bh!3Ydpu4n1E#9Vrwm`@srMf}^`O%K z$}FQ>IZmVH>9NtLcG9oEujY!WbthA1q&O*4UUuoWKNG&Y3eMepl5L%)B9%nRMQPT> zE(MOt3SA0bsUpJDod~{pGW#MC(*9c0c8(mY&sJiB%pB?&Cnj!6sM){Voo~*z*-x+| zyBvS+=C*(&QjU6Q(Ch}bwa9)8xh_%lvEC(!gyW;bbGQ9a#X4k0s3*V zXsyRlWsevt8Fvf-!Id5fl)gz+3z8`%;JiraMhaB+r|to zgg8wdE|^7U@(FHjA1dPQ;a0!O6S0Mk`T7~om6nkDJzVQglj1VkotVrY?nf-y(xvG{ z>GeI5D~)Q7eQsb7%aL=tPSW&;`w{Ltj}h~1ysQKCCl&rsQgU7fPhj~t+n{+EAQWX4 z5Fnv;wJ#V4%`=pJn^6Qi`3|c@2aY%{lK`^cHh=%#_b_nP!tpp-!J_(q+VyLrjoM@)%kmM(rM~Np89^#s5y2etNgS zDcDZ^XtdsD?08=Tj>Ojq+vNfH+}g!>4oT`_?{LOwKKtUws`Io}O+*MLHPU_SM>UcVdLAYlQmrP!g4uxM?C+x8i4>F>&%j#Lm`1a;rO&0cM z%0w;_ToWA@x-T}5UoK5dRL`0SNcye^VQ%!@31iRa)P_HjBN6@);gqL=mfTEDeY2cv zrkA+oq3q=J37Y-QrbA1+PSmJ+qW;qeZ{DeA*E@1r_{LAZ9^p1`6+9%V|M^jjKx>RY z^<^)SEhIRa`xX_82*mCm<&Z>NRy)Bq+^1!!+DZ~Veynph?_p7cle)G-Dh#F7E26(F zq#-T%*0S~#vgWRO09fw3GzOIy@yBfe?{#3E} z!f!|OHFAqiY2tB*1TGG>kNJ<&Ew&yGDI#Li7++ma5r(PSk0@zDh{I7QX78`@kHh(+`*(-<($@zWzY47%E6ubQ{({#o9sT1DH0mRD|aH zz>B4@+V)1y6dpp(v_7W1gUGsW4U;OQT_>C=#By~~bpP`dD#7=^`sV6)?P@#j$wfV{ zE#8Soq4elln97@UMuo`V^lkwBq9Fvi}>g$sH-P==9Y!^_8TxK4GCoa`)EP zUk{gp7(z_7q?c@AC0bfqj;(Va=+P~s{z{%9r$sby$a?Is?pB)CP9klvsi~8aQuk@_ z<;e}g2TPs)i=cuLOTOvJF(E=Kh#_A49Nme%dOO5?6R~%geFs{jO-9XgT>=G{o>NfL z7mE7%=;aq@KM(V(&Kp*o10Nt~Dyaw&>4Fe<_sYC^*`ICaLo7*1vuttyyq=bnzt+%f_qMr$gjtBc?V_J_dXlF7MmW>FHkG#i*XZps9gac}-G3p8PiOLI|yUg|e1 zyjJZ)iv6m$K-!CNB_+IW|{FO8t9FMFjE336{kD!2!=ED1$0 zsyZzW8nAv}DyIYwHowB(BVf^1D8PAp&}zl-lkc=CgLca~hV-Pa z?Wp2p3^V}m`semff}Un@^k1wTdH^piEHMs^k|IJa&pIf z_EXFf9ft!SaJ%!ARn2R#p1Y=|r|mQV@3-E$>$YhsQ7PByl$KfoNz`mnekDc;^ZyRSWBYrC;rpYw%? zItT%vlukd4*o{d~&BnGsDU5(5t7CZ6C{!EnEM>0aWkGxH;QIoq*_R%+)E9?EQx44C z)6yAy2{aE#4^B}yB*^^F|FAD{%$rLh7AM|NZAs}O`yxrpI=u5Uw3;mW3CO-Yy-cc3 z?ftKnNR>Oa_)?qmeAdZ?E4$zk0M;UQI>0eo1wfwi=7j+YS}S{&PBoRJdHM{tg=d1TYG5G8*w zNU*;po<@P=N#SDV!=)lSp%y2r{`2+de%bremA|0{VS0UtaO6{S+OPTf?}(ScmO>=e zg?aukQN#&*bE-Bb5?cf7<_fP`yDic>Fpb*W*b)wOuxmIT3GX!d zS*_u>bC9L7{Yv}qV8Y*9ZM(saQQVzfUct*SMEOf)(!V++83 z?=F&|V7b?}RA8!&Z}1qvkW(c~d!QIEoe<2N$Ja+HYmX`(D#dUn$9aC2d_vjWq=W}R zYfN6j9Z?_4;E_)DD6*ZTwzV0PwodLo#yO~`tHR6AU&SX!B$QeV-E9Wp<_Tq= zriskAaz$+W)IQmEkk4MgU&RSn_JylA`I?8&R3VI(}gGS zg?9>MAvZd@vzviqe({qt1=P1 zZ#p(Dy?FZz3KgXts51O^G|Y*+-%Eri#=7)~_tCf|Z09|8+WWJw{fwO<=U3wm4mQ*q z6n5iBrex+_N!SeHtg=;!!^MmZvHc*8FkqS@#>jWwhBSX8{qt~M2Uo0+i z{W-8A$vch4!Ff{lMI=kuvqf1@@sg`sFr2(K&meivs*W0Ii|fnaCx@5-5?^2DA367KxDn#itPDKd))CE>P7=&G&ptWrIS=9v zQMW{+Mby01Ophlq^`Tpin|W-mM}bf8eS|=CJ!cb>n{(V#EH3vwEc4xd`V)F;&6mo` zX{hRtOF@0fGlbN+Zj^X0D}~bpTrBz0`gC>yJiU<1s)lN2L5TB0qnL+Gc`XAS1MiUW zM83Mu9sI$%#d~KTHuGBc!qZD#t2H%xj-<%4*@4Zyr zgoE`nzV`3pcm_T0A&wJL7W}X;EfGr8*{Og@+?FH&zuX{r)i@#!pPH1MY`r^wb?Hs_ zDTt<=@SVWhEuW^4Em;Ca(Z_eG;vaml)k@Q~VDv-m=;gs$-m2%}WvFf)McJEe@lSUb zvhP5dyZrD#K%}s_H_-VW!g1kXDG7lxuZmb^S_BN=3oU zLBuQIM~4&nI>=cjds&G~Bi`-50VIxM*JY08#zrlAA_q!^khbE1XU6k_X~Bkunc^j} z$kJk8PR2cTvkJ}^V@FY3Jb54@xm2DICkK(1a|;PwWJ!d z3kG_;%MU(o~7CR|qogWtgGZ%4ST!y|3@HV|t(V zm%0Jy$MlmiApDimNR9F_Ka!Lp1+8T_O}$43UZnNAp#0)D5vQ9yxJ`_I*y-+cKjF2o zg_H<6=(-yksBi^tZvDbr+e?mXh#x-w#q%zfXs>G#sp`oD5n)_8TL-?kBi^Rky@*0$ z_;c0k`3~2mq&zf-ne`ah<%UM5hMk-aXOY+9G~O{t@Wa_wl9kdul-uR$YmdpAXh13Z zX-&>6h;vU-jZN3P6gH!87MSpYmYq#;O|A*Vum)lgP>j60Q4az0&4^JiSn50RB-9eG zV!oPA%b4Ak9fY5YyuG2Ym(^}5JlBbfG$_qmlChsLCoJ%F=)Q9>qn{rw?dN{iDv}Rb z!YgruT48GBDB(}}o*%HVv0|*m3%hOJB~q*wBw_5-6toj}n-R1Sbv89SJeG4JdsXk| zGn>Ks!Ee&De5cd&T^X7O6*4k1mw$b5#7Z3lZyX9+){Rbszd`El`E9hn{zeUIVXFC} z3pTVEV}_%kCHaU0TG50we- z4_CQ56TOx7gT5Zh4}Qj38~IC!V@pFs`#qA$k%0KVRH735+ts?q@75_kb`f6BA;B9u z6E1}cOy4}eWDSR?Qw0c!Hn-t3LvYn}0mu7truNuNaAp63{GPSRCce(!yIXOrUWylv zUU28vJp9<~HwTB-60_Gg19dO2M*Vxi?B}Hflf;~pXC-FAAhXni36(ol?W>o*tpqsp5Oe9W z!oDqE;>ABpFZLEBZXm(Fww}VTH`T5D&JW513|eP6-8hrj^E2WX?OiYJ9PRPCb(z7ps`c0VZ$GS*w{(v0wXpn{D%>!x;|5%E$uVut(?;!uEDo2o z@{^`w7l=%;KGM(fRc3AWkKK3!;U^_3|1n-sEuLl{ri=T-<2Jpd^(|JB5fZ%3Ubu!$ z^QP0bi-`$`Gj8gYbJ_1@&Bb=xtSPQIy)T>k;^!fR_H2s&6yy?II3Lf*v#u`X7m{y3 zt_TFPR^(%rmxc105K8~=oL5NZu6_)f|%N|^=6Sj ze6UL_@_TXfJBLmW_-s9XywLZ=!y4>)JxoXzwOJ6zi3svO%EFyR`HEWNWPb9i_v06c z)GJD7?*ef-JyG@70c#(aHYU-R*1R2+2YEmJzJAoeRBV|6vkg09QDhZiTvT#$PPaAu zD3Nn@nBkS2DZjx{L5s{MY5#eQPeuz3`JX4a$MOVCIlwfIWfyk5Nf8hlTB+<2!4jhx z)qtjlSu~CQL9pHoJS@0mO$nIMf$m?6g11X7QM)>lHRto7Ff>Vvd zW`{72<*W74JW9rf_x9o(FGD@NQT9Sajb-ce18EybH}gtR!M%{AX5>?Smu`O0%c44_ z5#Ai=8}0#}fSzY)NB{2OrKzpsqY_s$o}(P{hu@NU`BvDGq9;0M@DdbSDcyT)H(8Qf zS_ z(^*esVMlYti!$@GXBg0v`btOm&u|KF@h#e+E1Jo{(0XERYAm*eNq9x*V&wa6B`WV$ zDYIe8dzM+Ov(r3%ExY+M4M00KEQs^!5W^$j}0^Tn-IyCEh(Bzp%)<>&&wfh zx~NF|z17BKV`YW8x;3KimbSHtzF&W>XIn>69Hg-Eg{g|YncqNDGrv%#EuLCM(_gv* zN!wqvRXrm+U2A#aX8woQ{tWwj>6KDlL>T-9I2X;fEYTUS7(j%|Qq0%|2AsuSnD{?m zV{L|~1)))uvjNy5PJx^RE{3n%k_4iSh${??hhG>HUH7#WlAG7_hkHqUWt<)^Mg=eL zW{35~i`Yw}<6q!%w_8u=F^eA99^c|KyXktX-Bm-d{{5t)SwSB8(M!WS1-(hqO!_{PR9wgn}%?%+>8~1sD z2UV)Iq9d}}ZXq5pF{4j&elppWKmZysQJMRyzIU@*i9ONexzUIl0-7 zx2~JNmGg5vMsro|3z)d5r<8UaW$dHmf<%$uZVAj)t2--j+D)69_bM3bJ#5uIAp@G zBdV*4i)F9gRW|y}dYK^WNv&K1RHX*|YaE==8F@6Q+}-R5wo)_b|{cPM&@J{TqoC3`e_ zn1>blwdv!{+`V+g;wFbKj_+mQl1Em&cl_Z;&HiL+INoD!*)WGNtq;nS)$@Bi<@}0p z$vuUXk_Au1aQi1yXBE56HF$Y}wD2kl_9>B?xKiUEy$;NGf#LpJ@ZMPg>%dWsf7cMd zgEa~@^;4Cgm0M6hIKVzhneyKy1WAev`x&^pqfLw1Vqs@}6b5Os<=nVNVa*4|W{qzR zX?x$~Sx%szot?>?we~aBFW^n^8MRsuq;}eF;LSU{pA~En%ZJFT?UoS6wlYm@)^`C8 zG+XfSphq8_M-*$w5evs^7PkpIe>J70dW~hPLzq`;SS7*H)lw?k&2)={xG}{K>eOrG zUP}^{?rRiBsWz(2fGD6isK`1=fbU@@iIU~1@8EPe=qOY2k4%}4%86BuUF~K(6PwTX z$M`sui0(bHF)3C5d@yhH)=RZ@P_@X_jB~y0v36xp4Oy%-^Z$IM&_XpeVk9-!&x}-+ zN`skd?!SjsYI?{G9nEo0=G$A;3)A68oewuiwNejE>n4j8#HG^OhcPzyYuW3OHeu7r zQ^8D11q`v|tz-r~rSHqByd9x$I#QJHH@V6qbkAJB;up8FYvR`TVzc_qFzn@1^#;&LI*YLvFAVG|@$!p&bYd6iPj8hv7#1Lm|k|5YgESq5h% zsGHb|ezD^xi_kL&fq^3qz&O^FQaeMJa=CCQq|G${$fS<-p5vZr=0I!6vW6ys+R%hz zQ_~S|P?e$^*6Art;)u7FrF5;-i)!sQdpvR6YoYY_-ovxT9^F`5_N6iuB8GLC6Oczn z9`eP>Vgm9k*zHQ_KdMTmoX$Z}oo$gYrnKXe|C_?n|NpkIy-Z^aTjw07z1T)0O6wjHNHOIADP30qO!QMv~z4+Y6 zD~C&nv#9OjydmZgAe(3-AT;GDq)qALV1B_$qrx@Fd8IRWtR4W-FVoPP{Q6&q9qSWx zB2nYRZHHyoegDjN!$v9oZBkQpn!W2rX?7j0&hgJH9?Lt(*j^AgXt%5SDvvDU>JX;5XevLh!Pu0-bG48H`W~-;_1phZT#Dp8*a!1+Z((A&$;kwlDSqZ_ zMf+vEGWKk?$|V1FLaAxG=_9DQ&v^7vj|41=nQ7$}4zAT;TU%KPZNnOZ-N*0nNHmI5 zY^Nn~E*R~VHIlIDkUgb;)DWL4hL!vZ8?OkaOpdgkol(^%((|*HW=A>vgC2N@vXt6c zSom}caav!kzudeIH-5;8tHLL2e7y!+8+%dgoH2N~xy^g=RdVez!;-hd(qMP0sTfonM^hilgUA9KrJoNtp0b0>8 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 7baf7ca2..bfc05393 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# code.textmode.art (✿◠‿◠) +# code.textmode.art

-textmodejs_banner +code.textmode.art — explore textmode on the web -| [![Contributors](https://img.shields.io/badge/contributors-community-ee8449?style=flat-square)](#contributors) | [![VitePress](https://img.shields.io/badge/VitePress-646CFF?logo=vitepress&logoColor=white)](https://vitepress.dev/) [![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-222?logo=github&logoColor=white)](https://pages.github.com/) | [![Discord](https://img.shields.io/discord/1357070706181017691?color=5865F2&label=Discord&logo=discord&logoColor=white)](https://discord.gg/sjrw8QXNks) [![ko-fi](https://shields.io/badge/ko--fi-donate-ff5f5f?logo=ko-fi)](https://ko-fi.com/V7V8JG2FY) | -| :------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [![VitePress](https://img.shields.io/badge/VitePress-646CFF?logo=vitepress&logoColor=white)](https://vitepress.dev/) | [![docs](https://img.shields.io/badge/docs-vitepress-646cff?logo=vitepress&logoColor=white)](https://code.textmode.art/) [![Discord](https://img.shields.io/discord/1357070706181017691?color=5865F2&label=Discord&logo=discord&logoColor=white)](https://discord.gg/sjrw8QXNks) | [![ko-fi](https://shields.io/badge/ko--fi-donate-ff5f5f?logo=ko-fi)](https://ko-fi.com/V7V8JG2FY) [![GitHub-sponsors](https://img.shields.io/badge/sponsor-30363D?logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/humanbydefinition) | +| :--- | :--- | :--- |
-Official documentation, guides, and examples for [textmode.js](https://github.com/humanbydefinition/textmode.js) - a creative coding library for real-time ASCII art on the web. +`code.textmode.art` is the central documentation home for [textmode.js](https://github.com/humanbydefinition/textmode.js), with core concepts, API references, practical guides, examples, and integrations for creative coding on the web. -**Live site**: [code.textmode.art](https://code.textmode.art) +Whether you are installing `textmode.js` for the first time or extending a sketch with ecosystem add-ons, these docs help you learn the essentials, make your first browser sketch, and explore what the wider ecosystem has to offer. ## What's inside From 9fae97006eb3aae9a7988e35abc82b513f4ebe6e Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 15:01:30 +0200 Subject: [PATCH 06/43] docs: align CONTRIBUTING docs --- CONTRIBUTING.md | 18 +++++++++++------- README.md | 9 ++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af7daa1b..f61bebbe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,28 @@ # Contributing to `code.textmode.art` -Thank you for helping improve the textmode.js documentation ecosystem. +Thank you for helping improve `code.textmode.art`. -Start with the [contributing overview](https://code.textmode.art/docs/contributing/). For local site work, follow the -[documentation-site guide](https://code.textmode.art/docs/contributing/getting-started). Library changes use the +Start with the [documentation-site guide](https://code.textmode.art/docs/contributing/getting-started) for repository +routing, setup, workflow, writing, validation, and review expectations. Library changes follow the shared [code contribution guide](https://code.textmode.art/docs/contributing/code). ## Quick start ```bash npm ci -npm run dev npm run build ``` -Create a focused branch from `dev` and open the pull request against `dev`. Include screenshots for rendered changes. -For contributor registry or contribution-type catalog changes, also run `npm run check:contributors`. +Create a focused branch from `dev` and open the pull request against `dev`. Discuss major documentation structure, +site behavior, integration, or generated-content changes in an issue or Discussion before implementation. + +Update relevant guides, examples, and site configuration when behavior changes. Test rendered changes in a real browser +and include screenshots or recordings for visual changes. For contributor registry or contribution-type catalog changes, +also run `npm run check:contributors`. Read the [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities privately by following [SECURITY.md](SECURITY.md), not through a public issue. -Need help? [Open an issue](https://github.com/humanbydefinition/code.textmode.art/issues) or +Need help? [Open an issue](https://github.com/humanbydefinition/code.textmode.art/issues), +[start a Discussion](https://github.com/humanbydefinition/code.textmode.art/discussions), or [join Discord](https://discord.gg/sjrw8QXNks). diff --git a/README.md b/README.md index bfc05393..de47dc20 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,9 @@ npm run preview ## Contributing -We welcome contributions! There are many ways to help: +Thank you for considering contributing to this project! (✿◠‿◠) -- **Suggest fonts** - Know a great pixel font? Add it to the showcase -- **Share sketches** - Create example sketches for the documentation -- **Improve docs** - Better explanations, code examples, or tutorials -- **Report issues** - Found a bug or typo? Let us know - -Ecosystem contributors are credited in this README and on the site. See [CONTRIBUTING.md](CONTRIBUTING.md) for details. +Please read the [Contributing Guide](./CONTRIBUTING.md) to get started. From c4720b56dc71fe5cdd90a115782a67a1e9d9a4b4 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 15:02:35 +0200 Subject: [PATCH 07/43] docs: remove redundant README content --- README.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/README.md b/README.md index de47dc20..ac3c8760 100644 --- a/README.md +++ b/README.md @@ -20,24 +20,6 @@ Whether you are installing `textmode.js` for the first time or extending a sketc - **Font showcase** - Curated collection of compatible pixel fonts - **Integrations** - Guides for p5.js, Three.js, Hydra Synth, and more -## Local development - -To run this documentation site locally: - -```bash -# Install dependencies -npm install - -# Start dev server -npm run dev - -# Build for production -npm run build - -# Preview production build -npm run preview -``` - ## Contributing Thank you for considering contributing to this project! (✿◠‿◠) @@ -79,23 +61,6 @@ Contribution details and profile links are maintained on the [textmode.js contri -## Tech stack - -- [VitePress](https://vitepress.dev) - Static site generator -- [vitepress-plugin-sandpack](https://github.com/jerrywu001/vitepress-plugin-sandpack) - Interactive code playgrounds -- [vitepress-plugin-mermaid](https://github.com/emersonbottero/vitepress-plugin-mermaid) - Diagrams -- [vitepress-plugin-blog](https://github.com/humanbydefinition/vitepress-plugin-blog) - Blog functionality -- [vitepress-plugin-codeblocks-fold](https://github.com/T-miracle/vitepress-plugin-codeblocks-fold) - Collapsible code blocks -- [vitepress-plugin-codesandbox](https://github.com/humanbydefinition/vitepress-plugin-codesandbox) - `Open in CodeSandbox` buttons on code blocks -- [Giscus](https://giscus.app) - Comments powered by GitHub Discussions - ## License Documentation content is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Code examples are licensed under [MIT](https://opensource.org/licenses/MIT). - -## Links - -- [textmode.js on npm](https://www.npmjs.com/package/textmode.js) -- [textmode.js repository](https://github.com/humanbydefinition/textmode.js) -- [textmode.js web editor](https://editor.textmode.art) -- [Discord community](https://discord.gg/sjrw8QXNks) From 97351faadc859295317cfb1322f876cc17ddf05a Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 17:03:00 +0200 Subject: [PATCH 08/43] docs: update `What's inside` section --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ac3c8760..39a4193b 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,13 @@ Whether you are installing `textmode.js` for the first time or extending a sketc ## What's inside -- **Documentation** - Installation guides, API reference, and tutorials -- **Examples** - Interactive demos and code samples -- **Font showcase** - Curated collection of compatible pixel fonts -- **Integrations** - Guides for p5.js, Three.js, Hydra Synth, and more +- **Guided learning paths** - Start with installation and a first sketch, then work through lifecycle, grids, drawing, characters, typography, animation, input, fonts, and media. +- **Advanced rendering guides** - Build layered scenes with compositing, filters, framebuffers, custom GLSL shaders, 3D drawing, cameras, and lighting. +- **Interactive examples** - Explore live, editable sketches for core drawing, shaders, video and webcam conversion, p5.js, Three.js, and Hydra Synth integrations. +- **Live-coding workflows** - Learn browser-based sketching with editor.textmode.art and collaborative audiovisual sessions in flok.cc. +- **Ecosystem API reference** - Browse generated, typed API documentation for textmode.js and the official synth, filters, export, and FIGlet add-ons. +- **Gallery and creative inspiration** - Discover featured community projects, showcase sketches, experiments, and real-world textmode.js work. +- **Ways to contribute** - Find routes for improving documentation, contributing code, and submitting examples, with ecosystem-wide contributor recognition. ## Contributing From 25892aa06651b5a4e83442e6792facda490f5ea6 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 17:04:54 +0200 Subject: [PATCH 09/43] refactor: replace `synth.textmode.art` naming with `editor.textmode.art` --- .vitepress/data/gallery.json | 10 +++--- ....md => live-coding-editor-textmode-art.md} | 32 +++++++++--------- docs/live-coding-flok-cc.md | 2 +- docs/live-coding.md | 18 +++++----- ...xtmode-art.png => editor-textmode-art.png} | Bin 5 files changed, 31 insertions(+), 31 deletions(-) rename docs/{live-coding-synth-textmode-art.md => live-coding-editor-textmode-art.md} (64%) rename public/gallery/{synth-textmode-art.png => editor-textmode-art.png} (100%) diff --git a/.vitepress/data/gallery.json b/.vitepress/data/gallery.json index 4751689b..61424ea1 100644 --- a/.vitepress/data/gallery.json +++ b/.vitepress/data/gallery.json @@ -35,12 +35,12 @@ "featured": true, "date": null }, - "synth-textmode-art": { - "title": "synth.textmode.art", - "description": "Live coding environment for ASCII synthesis and algorithmic audio patterns.", + "editor-textmode-art": { + "title": "editor.textmode.art", + "description": "Browser-based live coding environment for textmode.js sketches, add-ons, and ASCII synthesis.", "type": "website", - "thumbnailUrl": "/gallery/synth-textmode-art.png", - "url": "https://synth.textmode.art/", + "thumbnailUrl": "/gallery/editor-textmode-art.png", + "url": "https://editor.textmode.art/", "author": "humanbydefinition", "authorUrl": "https://github.com/humanbydefinition", "tags": ["live-coding", "audio-reactive", "visuals"], diff --git a/docs/live-coding-synth-textmode-art.md b/docs/live-coding-editor-textmode-art.md similarity index 64% rename from docs/live-coding-synth-textmode-art.md rename to docs/live-coding-editor-textmode-art.md index 513af023..47972b1d 100644 --- a/docs/live-coding-synth-textmode-art.md +++ b/docs/live-coding-editor-textmode-art.md @@ -1,29 +1,29 @@ --- -title: synth.textmode.art -description: Use synth.textmode.art for browser-based ASCII synthesis with textmode.js and textmode.synth.js. +title: editor.textmode.art +description: Use editor.textmode.art for browser-based ASCII synthesis with textmode.js and textmode.synth.js. --- -# synth.textmode.art +# editor.textmode.art -[`synth.textmode.art`](https://synth.textmode.art/) is a browser-based live coding environment for procedural text generation and ASCII synthesis. It combines `textmode.js` with `textmode.synth.js` to provide a focused workflow for building animated textmode patches directly in the browser. (〜 ̄△ ̄)〜 +[`editor.textmode.art`](https://editor.textmode.art/) is a browser-based live coding environment for procedural text generation and ASCII synthesis. It combines `textmode.js` with `textmode.synth.js` to provide a focused workflow for building animated textmode patches directly in the browser. (〜 ̄△ ̄)〜 -Unlike [flok.cc](/docs/live-coding-flok-cc), which is built around collaborative sessions and multi-tool performances, `synth.textmode.art` is a dedicated single-surface environment for writing and iterating on textmode synth sketches. +Unlike [flok.cc](/docs/live-coding-flok-cc), which is built around collaborative sessions and multi-tool performances, `editor.textmode.art` is a dedicated single-surface environment for writing and iterating on textmode synth sketches. - + ## Getting started -1. Visit [synth.textmode.art](https://synth.textmode.art/). +1. Visit [editor.textmode.art](https://editor.textmode.art/). 2. Start from the default sketch or open the **examples** tab from the system menu. 3. Edit the code and let the sketch auto-run, or press `Ctrl+Enter` to run it manually. @@ -31,7 +31,7 @@ The editor saves your code locally in the browser, so you can close the page and ## The synthesis model -`synth.textmode.art` exposes the standard `textmode.js` sketch API through the global `t` variable and adds the source-building functions from `textmode.synth.js`. +`editor.textmode.art` exposes the standard `textmode.js` sketch API through the global `t` variable and adds the source-building functions from `textmode.synth.js`. The core idea is that a textmode frame is split into separate channels: @@ -64,7 +64,7 @@ This patch uses three different synth sources: ## Character maps -One of the most useful controls in `synth.textmode.art` is `charMap(...)`, which limits the glyph set used by `char(...)`. +One of the most useful controls in `editor.textmode.art` is `charMap(...)`, which limits the glyph set used by `char(...)`. ```js const matrixData = noise(4, 0.2).pixelate(30).scrollY(1, 0.2); @@ -78,7 +78,7 @@ Changing the character map can completely change the look of a patch, even when ## Layering -`synth.textmode.art` supports the full `textmode.js` layer system. You can stack synth layers with different blend modes, opacity values, offsets, and rotations, then combine them with direct drawing commands. +`editor.textmode.art` supports the full `textmode.js` layer system. You can stack synth layers with different blend modes, opacity values, offsets, and rotations, then combine them with direct drawing commands. ```js t.layers.base.synth( @@ -119,7 +119,7 @@ If you already work with Hydra-style source chains, the workflow will feel famil ## Sharing -`synth.textmode.art` can generate share links that encode the current sketch directly in the URL. When a shared sketch is opened, the code is shown behind an unlock step before it runs. +`editor.textmode.art` can generate share links that encode the current sketch directly in the URL. When a shared sketch is opened, the code is shown behind an unlock step before it runs. ## Related APIs @@ -129,5 +129,5 @@ If you already work with Hydra-style source chains, the workflow will feel famil ## Resources -- **App**: [https://synth.textmode.art/](https://synth.textmode.art/) -- **Repository**: [https://github.com/humanbydefinition/synth.textmode.art](https://github.com/humanbydefinition/synth.textmode.art) +- **App**: [https://editor.textmode.art/](https://editor.textmode.art/) +- **Repository**: [https://github.com/humanbydefinition/editor.textmode.art](https://github.com/humanbydefinition/editor.textmode.art) diff --git a/docs/live-coding-flok-cc.md b/docs/live-coding-flok-cc.md index ca12d54a..abf56453 100644 --- a/docs/live-coding-flok-cc.md +++ b/docs/live-coding-flok-cc.md @@ -17,7 +17,7 @@ const flokItem = { [`flok.cc`](https://flok.cc/) is a collaborative live coding environment that runs entirely in the browser. `textmode.js` is integrated as a first-class panel target, which makes it a strong fit for performances where ASCII visuals need to live beside Hydra, Strudel, Mercury, or other browser-native tools. (ง'̀-'́)ง -If you want a dedicated solo synth surface instead, see [synth.textmode.art](/docs/live-coding-synth-textmode-art). +If you want a dedicated solo editor instead, see [editor.textmode.art](/docs/live-coding-editor-textmode-art). diff --git a/docs/live-coding.md b/docs/live-coding.md index e3916416..927c7193 100644 --- a/docs/live-coding.md +++ b/docs/live-coding.md @@ -1,6 +1,6 @@ --- title: Live coding -description: "Compare the two primary browser-based live coding surfaces in the textmode.js ecosystem: flok.cc and synth.textmode.art." +description: "Compare the two primary browser-based live coding surfaces in the textmode.js ecosystem: flok.cc and editor.textmode.art." --- @@ -23,7 +23,7 @@ const synthItem = { `textmode.js` currently has two distinct browser-based live coding surfaces: - [**flok.cc**](/docs/live-coding-flok-cc): a collaborative performance environment where `textmode.js` sits alongside Hydra, Strudel, and other live coding tools. -- [**synth.textmode.art**](/docs/live-coding-synth-textmode-art): a dedicated single-surface live coding app for procedural ASCII synthesis built around `textmode.js` and `textmode.synth.js`. +- [**editor.textmode.art**](/docs/live-coding-editor-textmode-art): a dedicated single-surface live coding app for procedural ASCII synthesis built around `textmode.js` and `textmode.synth.js`. Both are browser-native, fast to try, and built for playful iteration. ヽ(⌐■_■)ノ♪ @@ -36,11 +36,11 @@ Both are browser-native, fast to try, and built for playful iteration. ヽ(⌐ - Best when you want collaboration, audio-reactive visuals, or cross-tool performance setups. - Detailed guide: [Live coding with flok.cc](/docs/live-coding-flok-cc) -## synth.textmode.art +## editor.textmode.art -[synth.textmode.art](https://synth.textmode.art/) is a dedicated live coding app for procedural ASCII synthesis. It uses `textmode.js` as the rendering core and exposes `textmode.synth.js` globally, so the workflow feels closer to Hydra-style source chaining, but with separate channels for glyphs, glyph color, and cell color. +[editor.textmode.art](https://editor.textmode.art/) is a dedicated live coding app for procedural ASCII synthesis. It uses `textmode.js` as the rendering core and exposes `textmode.synth.js` globally, so the workflow feels closer to Hydra-style source chaining, but with separate channels for glyphs, glyph color, and cell color. - + - Best when you want a focused textmode environment with built-in examples, share links, and a stronger editor experience. -- Detailed guide: [Live coding with synth.textmode.art](/docs/live-coding-synth-textmode-art) +- Detailed guide: [Live coding with editor.textmode.art](/docs/live-coding-editor-textmode-art) diff --git a/public/gallery/synth-textmode-art.png b/public/gallery/editor-textmode-art.png similarity index 100% rename from public/gallery/synth-textmode-art.png rename to public/gallery/editor-textmode-art.png From e80e00674fae251dbd19ac81c3589c0acffcba58 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 17:14:50 +0200 Subject: [PATCH 10/43] refactor: remove dead `createFilterShader` link --- docs/shaders.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/shaders.md b/docs/shaders.md index af5fd47c..d40fe515 100644 --- a/docs/shaders.md +++ b/docs/shaders.md @@ -130,7 +130,6 @@ See [Framebuffers](/docs/framebuffers) for offscreen rendering patterns. ## Related APIs -- [`Textmodifier.createFilterShader()`](/api/textmode.js/classes/Textmodifier/methods/createFilterShader) - [`Textmodifier.createMaterialShader()`](/api/textmode.js/classes/Textmodifier/methods/createMaterialShader) - [`Textmodifier.createShader()`](/api/textmode.js/classes/Textmodifier#createshader) - [`Textmodifier.shader()`](/api/textmode.js/classes/Textmodifier#shader) From 9d502c034964f1bc786537291f041ea1b77959a4 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 17:15:09 +0200 Subject: [PATCH 11/43] fix: updated API link --- docs/exporting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exporting.md b/docs/exporting.md index 188ddb50..f5472bc2 100644 --- a/docs/exporting.md +++ b/docs/exporting.md @@ -281,7 +281,7 @@ GIF export works by registering a post-draw hook and capturing the next rendered ## Video export -Use [`saveVideo()`](/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md) to record future frames from the final presented canvas and save them as video. +Use [`saveVideo()`](/api/textmode.export.js/interfaces/TextmodeExportAPI#savevideo) to record future frames from the final presented canvas and save them as video. MP4 is the default format: From f10158908023daa2f9ea1920cb1cc2557a2216bd Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sat, 1 Aug 2026 18:07:53 +0200 Subject: [PATCH 12/43] docs: enhance exporting documentation with example sketches and JSON structure --- docs/exporting.md | 54 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/docs/exporting.md b/docs/exporting.md index f5472bc2..9464eae2 100644 --- a/docs/exporting.md +++ b/docs/exporting.md @@ -21,7 +21,17 @@ const t = textmode.create({ }); ``` -Once installed, the plugin adds runtime export helpers directly to your `Textmodifier` instance. +Once installed, the plugin adds runtime export helpers directly to your `Textmodifier` instance. This small sketch is +ready to run and gives you a frame to export: + +```js +t.draw(() => { + t.background('#10131f'); + t.char('@'); + t.charColor('#8ee6c9'); + t.point(); +}); +``` ## What can be exported @@ -34,7 +44,7 @@ Once installed, the plugin adds runtime export helpers directly to your `Textmod - animated GIF via [`saveGIF()`](#gif-export) - MP4 and WebM video via [`saveVideo()`](#video-export) -## Two export models +## Choose the right export `textmode.export.js` has two different export paths, and the distinction matters: @@ -117,7 +127,8 @@ t.saveJSON({ }); ``` -By default, the exported document is a [`TextmodeSelectedDocumentJSON`](/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md) object with `format: "textmode.document"`, `formatVersion: "2.0.0"`, `target: "selected"`, and: +By default, `toJSON()` returns a [`TextmodeDocumentJSON`](/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md) +for one selected layer. It has `format: "textmode.document"`, `formatVersion: "2.0.0"`, `target: "selected"`, and: - canvas dimensions - grid dimensions @@ -125,6 +136,26 @@ By default, the exported document is a [`TextmodeSelectedDocumentJSON`](/api/tex - per-cell character, foreground, background, and transform state - optional metadata about export time and generator version +The cells are plain rows of objects, so the payload is easy to inspect or save without learning exporter-internal +TypeScript names: + +```json +{ + "format": "textmode.document", + "formatVersion": "2.0.0", + "target": "selected", + "canvas": { "width": 800, "height": 600 }, + "grid": { "cols": 80, "rows": 38, "cellWidth": 10, "cellHeight": 16 }, + "layer": { + "id": "base", + "cells": { + "encoding": "object-rows-v1", + "rows": [[{ "x": 0, "y": 0, "character": "@", "foreground": "#8ee6c9", "background": "#10131f", "transform": { "invert": false, "flipX": false, "flipY": false, "rotation": 0 } }]] + } + } +} +``` + Example with explicit formatting options: ```js @@ -148,7 +179,9 @@ t.saveJSON({ }); ``` -All-layer JSON exports use [`TextmodeAllDocumentJSON`](/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md) with `format: "textmode.document"`, `formatVersion: "2.0.0"`, and `target: "all"`. They include hidden layers and preserve each layer's `visible`, `opacity`, `blendMode`, `offsetX`, `offsetY`, and `rotationZ` values. This is descriptive layer data, not a flattened composite. +All-layer JSON uses the same top-level format with `target: "all"` and a `layers` array. It includes hidden layers and +preserves each layer's `visible`, `opacity`, `blendMode`, `offsetX`, `offsetY`, and `rotationZ` values. This is +descriptive layer data, not a flattened composite. Available [`JSONExportOptions`](/api/textmode.export.js/type-aliases/JSONExportOptions.md): @@ -281,7 +314,7 @@ GIF export works by registering a post-draw hook and capturing the next rendered ## Video export -Use [`saveVideo()`](/api/textmode.export.js/interfaces/TextmodeExportAPI#savevideo) to record future frames from the final presented canvas and save them as video. +Use [`saveVideo()`](/api/textmode.export.js/interfaces/TextmodeExportAPI.md#savevideo) to record future frames from the final presented canvas and save them as video. MP4 is the default format: @@ -354,21 +387,10 @@ Use `transparent: true` only with WebM. MP4/H.264 does not provide portable alph - [`ExportPlugin`](/api/textmode.export.js/variables/ExportPlugin.md) - [`TextmodeExportAPI`](/api/textmode.export.js/interfaces/TextmodeExportAPI.md) - [`ExportOverlayController`](/api/textmode.export.js/interfaces/ExportOverlayController.md) -- [`LayerExportOptions`](/api/textmode.export.js/interfaces/LayerExportOptions.md) - [`ImageExportOptions`](/api/textmode.export.js/type-aliases/ImageExportOptions.md) - [`TXTExportOptions`](/api/textmode.export.js/type-aliases/TXTExportOptions.md) - [`JSONExportOptions`](/api/textmode.export.js/type-aliases/JSONExportOptions.md) -- [`JSONExportTarget`](/api/textmode.export.js/type-aliases/JSONExportTarget.md) -- [`TextmodeSelectedDocumentJSON`](/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md) -- [`TextmodeAllDocumentJSON`](/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md) - [`TextmodeDocumentJSON`](/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md) - [`SVGExportOptions`](/api/textmode.export.js/type-aliases/SVGExportOptions.md) - [`GIFExportOptions`](/api/textmode.export.js/type-aliases/GIFExportOptions.md) -- [`GIFExportProgress`](/api/textmode.export.js/type-aliases/GIFExportProgress.md) - [`VideoExportOptions`](/api/textmode.export.js/type-aliases/VideoExportOptions.md) -- [`VideoExportFormat`](/api/textmode.export.js/type-aliases/VideoExportFormat.md) -- [`VideoBitratePreset`](/api/textmode.export.js/type-aliases/VideoBitratePreset.md) -- [`VideoBitrateMode`](/api/textmode.export.js/type-aliases/VideoBitrateMode.md) -- [`VideoLatencyMode`](/api/textmode.export.js/type-aliases/VideoLatencyMode.md) -- [`VideoHardwareAcceleration`](/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md) -- [`VideoExportProgress`](/api/textmode.export.js/type-aliases/VideoExportProgress.md) From 91b9fef12d83586591cf50ab86d0fa92e1dd1f90 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sun, 2 Aug 2026 10:50:33 +0200 Subject: [PATCH 13/43] docs: add back to top link in README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 39a4193b..55a93ec4 100644 --- a/README.md +++ b/README.md @@ -67,3 +67,13 @@ Contribution details and profile links are maintained on the [textmode.js contri ## License Documentation content is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Code examples are licensed under [MIT](https://opensource.org/licenses/MIT). + +--- + +
+ +
+ +**[↑ back to top](#codetextmodeart)** + +
From 90cc768132a45bb7846749877eac9113cded6688 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sun, 2 Aug 2026 12:35:53 +0200 Subject: [PATCH 14/43] chore: standardize on Node.js 24 LTS --- .github/workflows/contributors.yml | 11 ++++++++++- .github/workflows/deploy.yml | 17 ++++++++++------- .github/workflows/reconcile-contributors.yml | 15 ++++++++++++--- .nvmrc | 1 + package-lock.json | 3 +++ package.json | 16 ++++++++++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 .nvmrc diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 5ab80ed6..cf04153a 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -43,10 +43,19 @@ jobs: exit 1 - name: Checkout canonical source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@v6 with: persist-credentials: false + - name: Setup Node + uses: actions/setup-node@v7 + with: + node-version-file: .nvmrc + cache: npm + + - name: Report toolchain + run: node --version && npm --version + - name: Validate registry, tests, and generated README run: npm run check:contributors diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 37c41b07..21247324 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,27 +19,30 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + uses: actions/setup-node@v7 with: - node-version: 20 + node-version-file: .nvmrc cache: npm + - name: Report toolchain + run: node --version && npm --version + - name: Setup Pages - uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4 + uses: actions/configure-pages@v4 - name: Install dependencies - run: npm install --frozen-lockfile + run: npm ci - name: Build VitePress site run: npm run build - name: Upload artifact - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 + uses: actions/upload-pages-artifact@v3 with: path: .vitepress/dist @@ -53,4 +56,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/reconcile-contributors.yml b/.github/workflows/reconcile-contributors.yml index 2d14773d..ff380ad1 100644 --- a/.github/workflows/reconcile-contributors.yml +++ b/.github/workflows/reconcile-contributors.yml @@ -66,7 +66,7 @@ jobs: - name: Create short-lived target token id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + uses: actions/create-github-app-token@v3 with: client-id: ${{ inputs.app-client-id }} private-key: ${{ secrets.app-private-key }} @@ -82,7 +82,7 @@ jobs: run: gh api "repos/humanbydefinition/$TARGET_REPOSITORY/branches/dev" --silent - name: Checkout target dev branch - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@v6 with: repository: humanbydefinition/${{ inputs.target-repository }} ref: dev @@ -91,11 +91,12 @@ jobs: token: ${{ steps.app-token.outputs.token }} - name: Checkout canonical contributor source - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@v6 with: repository: humanbydefinition/code.textmode.art ref: ${{ inputs.source-ref }} sparse-checkout: | + .nvmrc .vitepress/data/contribution-types.json .vitepress/data/contributors.json scripts/contributors.mjs @@ -103,6 +104,14 @@ jobs: path: contributor-source persist-credentials: false + - name: Setup Node + uses: actions/setup-node@v7 + with: + node-version-file: contributor-source/.nvmrc + + - name: Report toolchain + run: node --version && npm --version + - name: Resolve canonical source id: source working-directory: contributor-source diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..a45fd52c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/package-lock.json b/package-lock.json index cde4371b..c1ccc6bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,9 @@ "vitepress": "^1.6.3", "vitepress-plugin-mermaid": "^2.0.17", "vitepress-plugin-sandpack": "^1.1.4" + }, + "engines": { + "node": ">=24 <25" } }, "node_modules/@algolia/abtesting": { diff --git a/package.json b/package.json index 0776d7e8..d1baabae 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,20 @@ { + "private": true, + "engines": { + "node": ">=24 <25" + }, + "devEngines": { + "runtime": { + "name": "node", + "version": "^24.0.0", + "onFail": "error" + }, + "packageManager": { + "name": "npm", + "version": "^11.0.0", + "onFail": "error" + } + }, "devDependencies": { "@codesandbox/sandpack-themes": "^2.0.21", "@types/node": "^24.10.1", From a44c168188ee828cac001a3e5928b630fd8347f3 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sun, 2 Aug 2026 13:05:39 +0200 Subject: [PATCH 15/43] fix: update Open Graph image to new readme-og.png --- .vitepress/configs/head.mts | 2 +- public/png/readme-og.png | Bin 0 -> 53185 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 public/png/readme-og.png diff --git a/.vitepress/configs/head.mts b/.vitepress/configs/head.mts index c43f48ae..b4c6123c 100644 --- a/.vitepress/configs/head.mts +++ b/.vitepress/configs/head.mts @@ -54,7 +54,7 @@ export const transformHead = ({ pageData }: TransformContext): HeadConfig[] => { const defaultDescription = 'textmode.js is a lightweight creative coding library for creating real-time ASCII art on the web.' const ogTitle = pageData.title || 'textmode.js' const ogDescription = pageData.description || defaultDescription - const ogImage = 'https://code.textmode.art/png/textmodejs_banner.png' + const ogImage = 'https://code.textmode.art/png/readme-og.png' // Detect page types const isBlogPost = pageData.relativePath.startsWith('blog/') && pageData.relativePath !== 'blog/index.md'; diff --git a/public/png/readme-og.png b/public/png/readme-og.png new file mode 100644 index 0000000000000000000000000000000000000000..c529b89912c227430205cb0ac6bfe7ab7c29959a GIT binary patch literal 53185 zcmb5WcU03^7d9GY6c90tD2TLSL_v|F2uKM*7(tXOC?X{yA|0f6qS9uh3ermilwPDu zje=5zAT9KW)PxdR0wg542S;Y!_g&w2@4Eb3NKl|DFOHW6G{mAJf5D0`_ z^Tr>yA&_6*K_CY`Sq_3%KK#DK27z!uH2=6}=$*DS!Pa1U$A`i2h>eS33y$IYjrEzz zhfgZU&tBt1ie8YpZeLk^|HP_O;|U_Rpz1}ap|q(Ixj`zNc`jf$%CUx>=+vn0Jv z`tyKL+Apjf&t_&!U8%&?Z{&_5WBZ}e#AKK?a#GSfEFFef8j-HRd`YIITNk?=1`h(! zyET1u@Bh~c+bS%3zsL;M`|qshiD{)PRN*NfKYq+fbegEEvgjVKb%Q0YOg1X+_;jAn zO_Hj?1^N{e%%b7Fkwc{j!8>U0weK_YL?nZnlbG?OnU&rCoKBie`3mNYz}lZVGH@DR zw||yL`f<`J>K4)Yp0po%$=zqH+L1kxytS3vRd~1fW+Jx8xZl0oXFff#WTeb8%r>XA zRMKqny^Cd?e~8HImdWsyr&leOq9+YXYaCK#9q+fKh?`U= zog%y03Gz}-^=i~FM=7q{NYqu{dDMS|G++S!{Q6)V$DZ9(v`Hy^!YAE}g}M&v$!Z=t zEBy-PsUs>JSvGP$uII3afav0Et~o+Rfp@^?bx|V9w^2Ly`Sq8ZlENYbm{)#wvT7K;s6uNhYfLwwm%K`9?uX8S+3syKeV4IoFSJzWJIvq|KbiDF)*cT%7(64W) zOnqY}xWuqm05NcG`cDeh{RM+mK#{lbaTgG^&D_0sLFA~ur>qT}SQ4lTQIUE1^IB$4 zTN!#CB?zdd^M!uVI`zA(7;hnoVpldAT6=Ri)%BKt;~^Mm7OPzwIJ@OWjYMYR%#&<#|c;4P9*dwW*13^Y^J zQlkEe)yy*qvR2TtCYxiOU$4h`c?Ix|`h``b8jrMAL(3gM(1Z3=Bo`t<{(s`PSb4=U-*MBtjkq_}?FcT@^g8O6@OS zthYCLO#L3|!;Os8y)l`S zsy8ODRxcKMhVr(bk$riu!Mp4)ywI03Z^ESD>B-w|znN9p-KlGM+?|qRe+3Jyw2=M# zn=ri@yinzcS%^?ALO=U+bwyb3*@m!Qx_UHHN0mXn&SM!f+NQo;14$B$_~Fq8r2PjF zKdrj%?lr7BC;rRRC$UFvJ{ECGW~*8UDL`M5)+>h7-rXbHWcfDky3YnT>m1r( zLpkfg4e0vn8)6queo?!9t%G&eT7QFMv@%E?pU?Vg$|P@>{8PB0+-TBAX(&Ty1aQ?)yvxS;o^!e$C*l*5H8!r>uya zC@EKs#hd~TC>48)Ifds;9!&@5$VV?NbR%?ymF^4=bXq1p^*ngo>3QX;(mj;OYWy2f%+{qRCg6-w6#ZVA;tDxUew1r`He5q zCPNEX&dnUX1R}g3@WF!*pOP+Hy^y~Q9awUB^8M3a_;NAcf$69c1X|gwx{do}o!^tz z2%dATbQ(3AK&66zJUSosvu4hO@ya=AVbeemX_tCTcwpalH8zH!4UbP=vJtsXft{V1 z_yoV;(7yCCCEYOb5;QZzuUEjzur$%{LwRNU>xqD$GS(>q*4J=tR*;q3XH&j{N!-vh!XtK26gQbFXSk&B&RBifMEm$;J zDqK8RTbpuib~u}RUM$-bKUO`}BLfwIyso(MGllvlN|>eWI&aK%<1Yjp!ziO_ELslt zzfhjGkG@ElCwzZG;;V}oq!gr29bW%aTbN7I+~J`w%LWSwD_wLe<^NAeJptK^-G0~Y zI0Yx!c`9f?S+*H{=)>-VA9X3cKt$*l;OS3OE_e$xD^2`X9pl5cXbM#U5pr}kS4`w6 zkCowqgWmkJa`Qm0R8Fog0c~(`sFE~2PNvA5JHL!FBPe1%J1&sNjk!8#X&2HfG9PdrYx&IQv~ zu9^6ZycUE3X9pp?`J<>nE);00=545Gvh5wj-73iH326XtsEv&n^o5LkBEK22jGXIW zHOqgE^w+nDK4VvkKcV@|G&}k(T;yVO57SxkSE%c=!9txqhnMFk26b5=c{!aVjuLa) zD|h29PWoyXBVD2&ybOMJPVPQ?mu~I9ETPy~Bsth&QiIK9ZE*?NP#=P>vd>D30QtieV;r6AwNh(sT{b3J9XS5ph1-1FFrP@od3MXd@k{iX zA~>-@gG}ny;tCB5D}Dc+ml-OsiA}XzV(isKm)QBuLz3PrGaYepv+0UnGz??6w4-=Q zUtO*Ir z54`rfLt)BXIXM6e_BGz(1MmGy-At^t(%dEFuBfupxL}w$awC;NuUi~i{N5$u*VQ3{ z8AP;WNxrl}BgDpA$$+!Q_sVCAbdeNG@x?e2^D#c}ui@qw7`qD^aCZuRgGMS}4H7h^ zWo$KI_)u$0)f|3cW_Xn%t~>WleD_&Vg=Sw-A(@ zX32a;eH#w(A-g=~dl0<$q)tjkC{s{gOI0!QNvDeNus6xv)QmS1) z(J6O!EpDlUGh_7;*7Nk6HY7#36SnREH^Xg89;4}E)kILYB7FlB#r^Z+p)U z!q;Cih$lio%R<@NX%uWKY|L5Vrg1;- z&B%y|H#O^M1~te)H$Bn(ignKtr>;^aUcHaEZXqkTra=RPq`Sp3W&}E>H$VjOd#l-F z>82&e*L(52v5K>dMck_=O7AnW!<60ex`FFVZj99>q8|>PTEyHUqP+GJ-ybcrg>2kt z<&_(jb0?2LZQo~x(rTEQP?s!2UHrCNFfZ8yw_60M9lCTPsTApjs3hzYy+a`}o9y@UPiPVPk{!9XxFV4-|MPcy7$K0b45O|y!z zjnTu&ux8o^sy3RM!>3-Ik3+A9V0?Q%`F~>)q_0JnI{JPsM9|hZdi>rjzUa`W$0jx? zwM3H1l#KeshM7{qHI{i4+6&h>?NRC%cfK7?>z@UkQ}N{7YHEK7l4PXI+VHg_ zP9y--fc4#G|J`Ync|F-$+xg0lW5Z^j(J^**USiW*D={PGU1$1S$lNL(B~Zl_2daf` z7%mS{wsmC|sY41ve2aWMw61=AJ#dvqWUNjQ>1~g8K>DZ|sjyC_qAJRF>h`&SA`$pb zzTeidbR^w!ay>y#*7WR7yw68A^DL|qYde zlE}ceE*C6PC*#8E6ag_`PMQ!(KGzo@clfEKfGpTbxODz5-=L<~;66E3@k2 zGETbcl2x=s#8tb^_pnKLo7Smg7n`oRG4eUcra+w&c$t(6ITZto~YLNwZz+CU9SwUJYJhy?QD|fPwE3 zW_=^9VuT3Lru0^AY-0>`p`d~KaF0AKi17RNVG7O>=axNtUHt}a8s3ELNo&FR?956! z%U&O@cBEpP$dPWCfKThQT>_New{xqaDJU)Fh=zshk}OKbd<&mAbwRXnCsX0`yIaW8 zODwYXLq&;=ORI88v4}Ea01>HWglC6GynucCJ_(XCpGV7~f%p5B2{ z8sbydWdzO04e<$-QP|ffX5HVv$;r`5UeDJJ7#L^h)9;k}2DqwZvGrJ^_VQB|7S8VTlu6~;;Tl1nx0WkhrnNheIag^k+7>(r*1@c5T=BSjD-J4v@f|vAwHpvshffLC z!@%{5)HR?iP99^UdZ)?3!Y?LQ39$$Mx$*bmWGl z39?8wZOfO(_)95ne7Rn}Tgsq>IQviEWSr!dRFIxat%|&l!OjgeCJFM%KxFQ zZ+6GwIB0MO?51);d&-RXYBL)uzlIEwrS3YamI2LXY)2#A;;V$ArGZ?1^$*|;J}b7{ zZUt~!ia*r(vA!H(q=&~kO@fW+KM&ta)wjnG{Kz*=#6yZ*|yYLkf zY2dds)Ah7-XfKLMc6xfOz=x!l4fuwQbmv=)Wby@^@1i4$v5T%RAw_vL+-Z^@>K)sy z#RSmFV?-$x2rd3IM~6PvJ-~Iqam2N7t6&b`?r;sIhu2+K?of7rT>(!X>wn~iK%G~^ zw4hd^C;$V1RS>d_tDDO$*l;j}l)rS*Fw2$Q6+ATC7t>U=UdP;afqDm~B;pW#*_TCT zLRWOxGBR{NxXkT%LLxgQvco}2-Vd;{BV@{qR>C~fRJj$@v5uY#H)~^7{iTjVum?bv z!B)D(=TQO;Uc};_j93wyzCFJq8GsMhRa$$J`%vNh@4F@FKpKugQxsrq!vj8xNr0TO z${pH*{y5;W$q{9|*B6vX!VX8>>DLiKDQ$rh-|Y|YQKkx=`*Mg|X(h=rszchc?cSaC z7QkIUEz5lh4F+^grCwm2tE!Rga3kmp(TAA@w->4`TGS2Lk!0($fyvcRI+$y7Vat-* z4N&B^WjHq~{$d)Eo{dp*d+G3KYX#<-G6Z+940sgitvH)b+zq3yjHO@nUo^ovyTzMkp=A^;cMxHS_|{gQ?=wjWF28Yhpb7w9NbY+x@9P%zeb|*cNAFOZoejh_ z1psc{*;ufirmB^E*|_!At5W-L%V?PF&Xf1nm<-_y<5l)XU6Grco5G4*GTeyR+K>Se zt8@Kv@jc^&MCA=P%>PBaBhO#&i*@i)v9T@irPkaT~y8KdR6-A9y7e9pm60jtUg z4wJw$n@L$#Y^Y?tLS3Cx5|4D6hgUw9k66AKU8I?ASj8J5zkN7>Y?Qb`$2-5i;K#`J zY&D2$D!wvKb4Q+bYCrLZ^99XY_nm5E+WMm;mJiluF&;=I3n1MXiYX0}HRFLx(+Kj~ z&?;Y*zi0R%zd;ieE-fAq0aTE{+T;C)a>lmx=zq)OInvyi%NRdlAGW>om z@ywYs6s#Zi# zG}wZEr9ADAD)dgbxCXzB%hxPs^j0G=K}HwpJHDD}d7H9IiDsrwY18m1<&_ak)4c>a zhxhny=fJ`P5cj{@l;#>hdXp({@Ff`>;W;x?w;1cj89D#Eu7YjP(ny8Ya==qvEhIBpUad8uJ@58VgJf~0FDQH?w$qk&Jg}GaOW3o8l>(?e{=9HRa z+c%qtmi+6T>0hQd>f+NTZzlTr-WTkAmU;JPuBJ)#xGxC)a{DD(q70tC$h`YPtf}d7 zH#AmnB@VUwXOZTLs#;@MQ}G9i!&k(E)90yiLX?XBuFa`#f2D;s`JHyhgY7W(@j#vR zvwbmoWfgI{l@8 zvyaw{n$|x*L{IG$A|`f+YMNTi5!>t@H+`UHJQuc}NmV=d-XY$uqN_n5z2`x;;O0{r z-X>K8ED?-PtH1>QDe#n#=0+b5-3%7l&8JIDYRl33GRlA76_{R(loJtZJO{|GISwKNXrNrRgrFgHrXjKYE{w{;eebm3rdjS{=6WJk8o$G7YU<+tqRFo&2tX_vS{% z){?dIMplkhhnfriZ7JXB)01^oNK8fxLXBU}X*bzgf-)zEw&PQ#uj!VWQKcK_3{aGX zwKl>^qoR%-J=#7E=!1DU!!{rrPZzPO_gubNQqq-D zH6*N03my~*iUa;gXiR(uA^~A9+t<@3CfGciKf2z z@YEqwB#mNUO0!)r`AX**rjwl!^PQaLl)l6TWM_l*xkXs#6E*qn6d5tcGMD8?`Er%c zxF%3FvgcNz!gVK?noX_NQDlWw3NnMiRNhgcxG1hT%~DC2nRe#K}fi zP9CQL&k?II-uYN~FOE9tm8<47I^(w-LjBH-PTRFUwk4u8^*tOlx%%t%#bs@Y(@krw zh&_}my@edzoe_b5&nGUXj=Vcp%VtYsLwMU#l7)9p#rT&rfnKo#4yTSp=jJlas`rZv zi?n8tin!aEdCeYo;g0f=Wm>xie}yhKh(b zjU(Nfxrss#x8RZVgJU~4Pp?W>lnbKBg3vNI=xA))r(=hCBN~N!S1t@R$9-_HjsCw- z79}gE`1mL0>qO;04!k?Z|E$-oIDwb-SLK1sMv;*f{cZND1`Tbt_3>;`eYMa~oO|ee zSst&Q&%nqb`RKY;-V6CTp#0|N;j)#s@}@5&az-AGhgGiGi`gAM_zOX!RU{tM%I`1BUb2rzwA)rmw}`%CP_4EPy1_fjoCR zl=r5`u7HeqyIXWt<#Hw`pmBFA;8Zrw{Ned_2~m6=n~wuqzU>&h&np_=9X(x#9FdB; z5Rn(IrvvxK1ilP$r{Q-WE3+`7VG-JL34~mobi1cz4`~#VJ}I1AkWQ|$f9QK%dtQ2< z3s97gptO3l(1$02R7Jw1AAga$w3M&x-c=7fY>Px9>l*9^3*3D`v}j`&oc88&3L=1h zwyZ0n9+pYxyNP_fT@<9Ccm!E&&oh|<7Y-AOPni&`_gEZqug$Am{V^B^+F?HtA6??ZVg-}tJg5@CKUMa4 zpvMEyuqx#gZNqqQZwU8c4#P_8xa}=>zbyat%HBA^<&PG(X0m8@m|j0ExEVfVJSCj@IUgaY{5wk!<}K-pEN}5XMxNEOp1JFB^m)6|Ew}Fdd-eNgGGBL5 zC|I5H2kl+~MopdTB)E|4JZ>W)VrQW4W!9%1bnn}2U~+Hjh^m6wz%rlltEOv^1@rx} zs&KI7FL+LpWxlfM4O!7M;dSNL{;$cpuhJ9*wT2dbU`4t#O&NT{Z|#+sdCOb*swQ$lJX_}D%BxRMt~Eq zyLH5#J#;tf?J_8MU>1+HGs-eor{!p;_F4HzR`Yv}yWrQGL)fybow1u_`kK84*}(|V zEIB*@;@vU`pgGu^BYhs)S8c>A|4<&7utFA2XkvnUdN(Nw&WIbaInq~2P!wX+w_qk2*XYN0>I3~^W7cT?u$s>zmmx3BrFTN1nrBQ&~_uQ zV+{4Yj*ceIjVS-e5lBU*wU-G;6unj=3KBP70za@Zt_7udX8y%Vv7?aJz9o(1(L9P9 z1}0a~G**MQY>RTQJ<_pU?Kq|t5yHl;?g$@RU43@|VhG)zZDz+QLRoWW(iUkA&WZd-e zU&?@)+=whRKi<4LFXl-lPsce5r~-3W9r}Ad8D6|U3nj>$Lz(`}~CgdcvM+KQg8dsm$Ad z{m;hFYUHqkKPq5vvJ zJj?-J{XY*90Sms|_WI3p@_5jjkY$a158#T9ZcL9Ue#w3i(y8)K!2OVNz4v7?^IRF{ zxr4UHmV7W7sc}aAHBwlnkAC?12oogz$#NA|eGuihQk$dmP!I(SnA2q?90%G*=}Ql{ zME=*5&JN#m-NY|>5C(uUCes~^^bdc|%w|%t7XQb7W{A>eK@^840^!{#96Uv>u;`Y|RL|E#L00aWx z4}~+wRnwVAyM)q%eLv}6Qc$o1l}y@G#|Dv-+mzm{!F32?$o$h`2YzME?18ixT&s*z z7UOe0m-Hhz^CNA09t1s=el_B0pvC3KcR^o&|I3X zcrw-OUK{bq6&N!|tHK%+RUjxJAPad)5ZbScjZ>k#StU=%Bi0&&V}E_$3sNh;;69*s zI`#hRrGu{xz##AV9Rvnj7^7i3-5Pl=VnXhexg@Ivm~D?R9Dt_D-nK+s4}qZo+VO3d zNsW_C@t1VPL~voyqJJZ@7GI`$J!9?00Z_3@D!WlfZkFdt-$BZrG8e3ekB|i+y^Z_% z@W>68kc=8BxL=9t&>{)))JbF~Lx*g79wo+lG@rTk@C5V8KEXXq5{BK+@3S{qJOpec z!`zP(e%1I4X!HY+*8)pvy-ini0~AA|FCKy99ozQ;)1Q`|$;2E9OJn^hxC7PVMdRlS zfZa(Alae)h)09E_az+D2n*B$Jc2WsyaYN@vthzS`vua}(*JRZOGBYavE;fTjP-`zH zN{yfi6!KK?A5-aT@SpSuslX^JnhlM-h5@P4kMPUnR8>41SG)bF5hjV?Cr~LAEwK`w z!hN+$Ah>AuL~R3=cf}$S1H4^j%vn) z)7tmX+E|=>zxH8BtHQpqjtK`hXVh>&o>F4`bw&J2USZ;Y2_0zB{izg-OM7?3UC{6b zaxdQsn(OW#Xeby+UdXODL^1`Q8Em&L^Z5ZkD*M#Kx_oP6poVjU{5J&R#W7 z`opRrN6NpEo}90i((P0NOTf3&@23iS+9zO{h-e`$(ZHaJ3Og6R_V zb%XV-iPH{$<7E#*%gDr2`f}UQnP6CyO?4#)r0&;!$7oaM8QkFL(@hezUi?uK3XKKJ zf8_6kws_{tOcowe(R`$VM5F&WQ*RGM^HA3V)b*b}OCtf{)D??|6-^E!54P!#3W<|G zESd)o4DjrKN@<47jXk(!mT}2az2&X6bClo%M!{ghU25xNbus3!bse1Ytn&-n6=b`|TnAr+_Jz^X`F-c75FdpMSK3jXBNk z%8w<-(mnP*%3V=Wq*8L3YeEssul~J-xZqv^`$_}%b6l~pgPG>2>&N8XwEnh{A0gZd z_i%(7hx}Qd!;2H?DifDZ6;@CYDBm9kT>l53rw9jwP9y!~n6?qhw`b^w+|Z~(Ic)-V zFJ!a40&hbdnf~+fEw%%%dH3O5E==KnbrR5-ZKS1Z>Bhp#yUdZvya5` z{~DeM_#+hE5)A*uOQn>Q#@~V9vlDr-?*NCHYEFvXJq1xA0njB}5a{k+X{Al4H^wx^ z&PX9|CjT4U|L^8@`*Nu*=^YT0Rh;Nd>G2de2QQ5Xc&PtO79O9tt14!L$@j8Fb(hi%e{>E5MirBoN!7Bk znps?6wGWG>+vkUiZ{d0hhs}WKY(yCd!ha;Vf2)HGPv?1A5%yutq8egTt$W`@JyQ$Vfmm=yNT?QZe?!E*IIl_l(lTNxm@wZZ{2`uC1N z2<7WneazeHJsD`ya$Ap@_e$-2O42enfcv?-^ewb*qM6TYonvMj99gu5|Goxa8uu72 zST*;#(BfAeA?y6V0VvU-QD^uCp?`xIoql9)q$!=llc*HzxfeJ47|4)VVpe~j3!h@3 zBY)P6jL{Wc$~a)e$V`%V%XwzPukObL`BN!7fDrYOV+V&Q?^eqzeOp_tXBeQbP{r^l zM9J9St<%DBlLoj=_LErrVr4QiP&E~HE3+tbg9D;x9s5gbl<|wK;E2mdAeJZh^A-lU zub@ZBbd+Mx6<)7_Jx{Ul+29)L1|vQT2xLN69e)(n_^z}RW2gyaz@7#F=@G<~uowX} z8QTw4|IZRcBIv7qUarASuG@i5wTuQ-KPr82Bb{NhGq*PQ1tAOS`wg&mQ=WLTg^zqD zY)G{EbC2dv{zGPwwj^$dWc-c%xJ)Ez&-yMcoVLG$A?HgLWHd?sS4}Vyc~*yd*O1mL z(<%D!zg(g$(eo|}hI{be1tHFd#Y4wNB>3`w`Nh?)1aW)gY|Px~e8%5~D^;Zdd^3N0 zY)?LzOyx8|3@8PsuTyahWi!v&XA1J}-D-c5v;P|u5M)Bi!ES)gA+@11(J>Vbe>=HX zwYiAHbrRmgj&Xe}u&r$cfC9>I`@paYGw(Q3{@E?Wtll&Eu6yLljm&^26A z+G67j(PQQm(a}l-@a6uH5rc%ospa{RJHHXu`u*-4#*)o^&XY#|k9Z*7Z?x#yz9+cM zI_zcd*SsMSgyh`4cIRnX@P0$p1}}XrPOjfB5AYk;H_{P>1y2D-aNJX@0sOvDISg2% z$Cl}z@w?&-%CJB)old`9qpSPChqM_4N<|sTk=7{+7Aal>ozfb&nS179UjUVio;fQi z$is7KO_}l)n(jH;@M!A8Gp1Hb@AkAH1J`9vzR3hxNaGS@0b3w5p)z|={@$7S-QA^~ zpXo%C>!Nq>CcYnbXitjQ1r64gMqLl*(n-Gj*(2Vq$M`V>!han^6ZrWlL+4Jm-E#*4 zzkX*2tZu5TxY@DfxF1bFC<lfWEUz z@tO+J1#>6HsKJxfZ=gHz9F=!6Juu&kCKVI?7t|OJpGv%>3q%USmCepG{jn2&AGIqG zFwJXp`a~E=-#`pf;k{S3WGi zhF47da4^S0L=|B-S7{a#H>(zQ?CqkTukU^HngNP^Ni7*nqatk2n%oy9ehtYDXNLuQ z9v3zBd0i-A8NCv81RtH%G)yU&+PUzfQGR+g7p2S?wv3iJS@GZ_&tb^Z8~k*Y;TTTk z-KqJ8DfZG!Co4RcF$}UZZhZ51{FWk+5H)S2i-~AGQBD$MZ09zu$CoCbp)xHm2bXdK zFPH*5MvHasn2e8DG`+iZQQX;QT2rK3)^Y1EUH>_5^zcHRA*#{o!aTooEiGyw_nF$% zN`u=NP}@oH#jNW%6WdGHwIACFquIm z<$NMnGO-la@eZwA2B?zITb6BcR|>*Hh1c80O}Lb==yK3zAQ6D1S}ni{0P{R*_1N8FycA z%jzgF2&=*UB_cp%sIa(yDz2eBjg*JgNx&!z*>K8N1v%Up&VOXUhyzp0 zi4B#W`2GXM4Txc-SZwPT4eXwLXanoq<3Hz3PtY^s)@`WVDaf=kbMXM7zq-MAFXc@UzP0rNWy0rS3Zf5wUECYac6&>DB)SV&1|D&3cGiIWQzZ9uY~n-pO?(^daief z$Q6|#?mD4qp8byN^WJn{S5=7RFpxTLhfCD;8h+VABS}C!&aHK>X1siM3JP!Yuzn3JnH6`>z@PTRL#E#a{a3Xr#R_)e2LcNf>*6fFVjutpbib4&?5oxOF4Npz1X zd~M3crDU@wEO^Kze&42?Lasr_?atR#&KkSvHvIxoN#$RA);oCiR3FU7I!Gcn&Gkh` z3TMy~5O=Q5Qyf4?hlu~f8Jr`)n@D6VU{s3G}iwC0VneD}`yyz*i) zrlI}L#wfPQr7OY2N`8#qRi#R>tU=|{g`mdkDcFYQJIRmmU`Y`xt$j#214zxY7gBM% z1@>%mxP~87{>8pW3=@GF;FElOd`EGD-3F-f74D{09;|vS^92TKfIMaPjb4BB*h=x- znz3CYgV!cLeuqx@`kN|2+e;a3CFaK&$5PGoeG|&A-RC^DG?Y0t<5kV5L7WTT_a|=DRh`8`|k;IX<%F| z?2o*n+X%NTOSOI|18W%DVV0A6EG!tax9I^p1lBymT#lXq9_1hfc^Y*AsF~8)Ctce3 zkqrk(Ua60QeC17a?m58C>68RqgY&`%2|MILUDe!&3~%kphWkuh7Ev^VQ0CM-bXY-{=~LzVVRZ>>o5Y_A-^2- zicSPc^UfPlqfTRDhL3=7Jp>_vkMb8P$C(-(* zx4^F(yOpTf=#0to{5mV?Amm)-3|=%FmOWb}(@{2qp4jzjI0H(VLuX*Z*7BH9tCJUg zDl+G^`u*zV5$OerTJ@}8b}}PIJE|-;>X}49_B!@fzcyaK(~Ra?GwyoJx4v~TM6#iBDpLpks>F;sZJ^`Q!=2thZU0h2 zQFBl@vQUGjv17O;V(ZUgkMPJCI-_U1RD0w<6v#s@TpfgUeM6UP(g+DYEcrkY3%bRH zcifE&Z%Z&oQ9EDSth*JydVJo5j^ykj+d&2CU*E$)X2QG!T_ftE%jO-8^jS%y3}94p z63@-EpeO@qExMZ-P1~756)V~H?GLA~5b5L{46?*!5lEJi40;YX`_XZG(3a$C9?x@Y zPLMt|e}Wn^SdRWSN|)?C$fBWo@2T)5U{w^MZnI%SU?d@Fob>0my=^`ZW)h__Z`0JL+y?FRE*HyrV z@$GB*UzFy}nH0lKsvVLSZ)s&^T3>#{E7j11rwhZuYIS0XG1v?Z_?(7Rzw7n`XMfOF z=dH%Aj}gD9-3Z9|d*QHh%pO54FhWyKwqClWw=U%QVpKg) zcoU~{6I-LD1eo!#jCWDS)Tf94ZuDNf`lVuH9+hzM3s9Vx0q*M;0=3a*u)z#a45)9 zoK-X>l2GR)>RtyqJ4d)=l-_1Hzou76VdXrR1mTGan}J5H;M1pk}6nwSFyu3oMOnd`Rl6_acr|*(V-2LfSwfYMx9T#J)w- zN#~dxbMYG)24UI?Yc!Wxd<@z1o{Ue0ciTo46|zf6aG}DBK~w9JjAc zXrv|dZRSK&WCCXTR_X2hiY_x>GVH=>nPr7Baf~Z}-_v_uw>H0uVqvqQkKjGGM5<`d+MGnayB6K1JP2D8nc+y=oco@uzK8Jldgww2#_rS z+Sv5qvIGe;!srgzHK{mvd+@S4WENlk11JL$yne9{Y);4($rD6zSG#O!AnQsHrkxH0 znT20(P>)nM8G&4^qs3}CuZ%PMzVENVvX4iu_fWvf%hv}-e*! zPP&56bFWb&=i(_jBpPk(Xp}q9(8MwNkO^DNUO_ zXKE(M^)u*Al<#jtU%!5JSHU`1tI_&Lh5hK0TTNrHev?1cl3HIUhQEv|GDY%KG~r*QypE=^8`*f9MV8Jr+KXS)lOYRKvH!?kW$z^+YfX1#p*GAnfK zz&ETIzYC>iZF@S}S+p;45{w#hPNs_jmE1eq$SY_WQ#+iyAD@D|4d7g!eV&RJBC%&L zj~wH>`r0q=1x>-K%hvH`Y(wXK?U@eC?~-|Qi8>}a*tp%>ugd1>*7EWP#i;xfp~Uc3 zLSG9n`>tecM}_G}jrv*pR~or1U-!D9V-wzAZlTQkl|SsUc_%?Pd`>%MVDtC%ZF~lj z>KP({z}`W%QAmsZvoZQAmW$mq{an*RywK*mu&UwqFy&22ECLy{*f)cPcb6oGNfk`~ z;RH7c=z=>mU($V0M#3kt{k1#>jc&s$Y^h#xdt^KK?G|tCEesg961vbbITdM9Q1J>Kk3Jf44y-{PKAoaK|%`q5!ammx8<}^Yg z%4hC(-H&Z>dWXAlXjGb#Px;g0npmgX0 zI-T0tA%aSifI_2-fX~98YX>2SiV>)bdPuvY zcww;nED`$)!LT=;Z?vS|iB?=QS%6)dY#cK{0{;C4=;B1@D8PgTY}GRyZ$1Ir%9l=w z1v04hK$v6wA|XxP2SEOBb(=uts_WZlpnZ&QGA}h*+FA*(sq1b=Sq+1K`Ryr^u7bV7 zs=zwnejy2M@ARV_KgBypZIA&QVur1%XuHCDWh?p?BdJZP)B9|6gmv3N4TVGBrf#y4 zavLOWvFvSCmzZq1HJ)QIS4ZtBEjK%K0|BH5v+BTRP6;V~R}4%MPRhsde6XKxP3^p@ z({pv&oe=|-ck#}464*%E$RJmuH&6I8sPG2RSOe8PXo4_FE@=lK5!ZqJt+ZGd2*)pG z`}NXAhes&)t~(+}D{b+vJjM@~$Us?yEoi1MP&k%-{IkeyQ6p^QsPZlN-N7hpf(ZeS z&+j4n6&1iTux2%MzzPjl(swrm(-}+_GC0ZI&8sYX_1bjgLHpbLvGLt$^8LSvDVo?b z$UlPQmp_TQIMoIQ$N>3w#OBJ#&F1rGs0O^<(bQnsMjOKC5-n8lZzM z%S$RoFEQu$sCNjYlDwGZ%hO?w^2OR}Ks?n|7=34+CTU46yS#*aa4gM{s($F(8@IvI z=)q7LO3LCntL$L`%x$D#;m-E^I%Y@u4(nN_O20#?kApNRm9B5y-eZ~J-p}$IK(EoU zYfqi#rGacl& z`Yopqm@NYuZx=|f9dyAmna75B&2BaR`Ws!yWk1lrqA}VCU+Qv=--YEgj%DuDWATl& z@OJtqWqKL5!V+lw08B3NK%$S+)J*0Eq%jfs~{l3@tk6+ihPS?54 zIbvR~=l#6z$NgCT*lUh*?3okss>}7zBD`dRPPDx?pk{2)x1TOf)bs4?a(UP%ek$V{ zmJxEgYfyRr9M6EbXGxYdTfIhR7wT-S&s>cIpH0N@ob@F!Iae2mNg1yi69<7Z*C5$ixEEXkGo;6W3&` zj~|1V$aZ|P;A~;7LO60KcUMgxYyX!x6cx@?xQ{W5f%Bt#xDI8$aGu|OjI-w=)Px$! zi`)~-W*V9vU*~LC6hyT?_PG{o*?@gvt>ZWnqkvnkhH`S#3X~C8+|Bg4$^%Bx3fJ%( z!N5p$J%D_B+TUZ&KbllM(Nw)R^8iCUSMowzgFR82D`n<59vfYVMSKBg-jft;^@Ebg* zzGlBW$cMT%QsL7@(bd(J(l@8C5;ti5Oz^bVE>Gtj}l(T0N4kY4+40smCFPDL4 zLGM-KyErn5962~DZ&mSp+&$Acj*UY^y3p0hwk!8Ov*kjOpXsTzpp}_^G-2Trs+uGS z6V`P_fZxu8pfZt6ou9YFENQl3r}}aIS>8%LswXyI83rkKBf#D>+m;(}w`!L!-Ywg} z{PNL-x!l(GJ&>5ea^_TL3&5DU(zt!J=-hpX&Ddl2BM7W-J4A4d$!VdI2H@IHnk!g2 zO-Ov2&uk4h%`z@NDj?;(#q_QcHeALq)}*~Y-(_FIbXEwk={R^5D#pgce7`P9x5Eyz-e>*fmn*!b5jyua|+Z2A=h4m|9_)hmGc+;gKp;schU$}-FMzjuQ(8_FF zKPTN)iatBA=dM&x1==ht3hc!MGk$})FO1J$A-}{7y9u;4gIX6lLE!XmC%Y}&nQ*iI zGaf_Tn{R~IYKvBkc_&S`>Ae{n#BxubREE!74Q~b5x~3{j1vVR^k|+RD3+;vm_HnC_5sh}aW?0_E`RuvBW|}Q#J?GF!`ciMDrwG)bE7vi*zqBQhq($#l zM4CnEYH*n%{V=mhjs-&@&MHX$K&*sfEB)_$5 zqbUH#)RNZ&twVNo-#(xl6MQ4~ou55A%u}bs- zKCEONm*d643PeKa(*b6w7QNVW+N^YPx~B~9>e%Lb(U!8bDJiHq%I=cJAl@+a*%oC=@MlC&O|X2t%iBC;kE|3b7O6W`o$f_uXa@C+7s&{ z)R>8hiCI1^kH(LRfH)_ms_#S5=>yddHobxF)vW(5du3JB7^9q7Ro0T>lHgr*)ZgJ* z+126tAn+k+G{C7f)@&B2WMq)%K9$4cj&u^#=IeubJ3Dd6<@UMsck zYK}1}EQ5%TQz8Fh`c|`VhHtzmRO5PQi` zu!&VQR8=D_+abOm_3-y#~H6YZ))whK)kp&7#($Y9JZhmqgbOC8Cf^|YF8f3N^WRRe~zjMdeSe-i2Wt&rnv=H1x z%*CJl3It;Lf|pl&R0Rf~oH99R5bAE589bieev1a(BgpckOy4dq$#2jW6%uN`;IK%# z>!?RGjX!+QDk@t^>%6M%uGz#J8eZT3ROxX%-!~I_EVNIH59PfPJ1ZAW0}bAwg1vZO zLXqdRb>LTra8|j3u5erZD5@)ZSm{$d#z+4s@S;1(u)A(m`P}~+-hqvgtevIa^DPFM z4f*3lOINPI=XZZxP9q^NOsVqhV{8MGbnnZP^;(+d6U?3n+}%=_ezB8X;j^!9^^Os$ zuE*@1J_lWGV@4NqjG_QQPlY=XF`x3H?rVNe71o|ecFY|@y-`tcI9$D+Ui^U7#->{& zTk?5-ijYQ(Kgc&S)tt1zyTfoeA-w0*&x`c#P+DcSSX1ntIM_2RL03>jZgulWwPDeS z4;?GJ z#ri;8?OLzF<(7W;$k(OJ+@_n-Akm<7*%oY#CoBYafnwV*x&+H2~ zeRH~LL#`Q!V*C>Xx}&>w^tXedL)*D?fiywcrWv9%9Z<;1;;YC%niyr=QHsbOuj*06 zbYInyT2Wq-N+s(Q-!6prtQ{+F{!4d|!Z-Fc84jguxi zJLvQx&VyIGOWf4$RQIzfWVBGC>9YfGpQL4G8e9vg!%nnw!$G(#N^s>P8C_+@o4MNG zlZd|Zf%?k`ipu=0L;Uddzrfe!IVDbwH8bk*(&{WZoHKo=Hnfu8>L2(?6=^pI|Cm9iBn_HS=bpPGzK-V$kyd=0Ux= z@XZ>%=cF6*n<{7oSC1GVPEAMAie?tWCTY%=gQ0;zS_5G7r(}0cURu0kuH%oZ{m3xF z+j~K=Q(+IxJw~_)k=QE1-U~netS7lu<+{1*J(A&#o;W%ZY!QCL&Z!j~;P|WAm0)h5 zk~bT6SmThJ*VZd6@K`vh4)E_)U7P(qo)_P@q#H%Yo|*4DGq2mNV3<2SC<#Q3+Vc{qMv)@-uJOsE~Tj_4o8FrW;|2HhDlX zQ_GuK_^n>;kS=?{!e(j$=#GiDVfGE--h2agnu^tBF=X=DTf5&h0)(bjWsf8Ic)4Gavp86VTh@+}!dr`24c_*fq$e%<7KvlhOJyQ<9E zr!mIkj-EPaBRO&>-x-MB@%<;-K=)M@DJ%b8uCx<%Lzzya+63f7%<*lqZfhf z-*FrX^4*#!6k8gzO0o)jv7=R72HGAMGn*@OqyDk7B0S|5!HqRpc(BC`hmS1Ra{6~* ztK>H8&AywxsUz}(xklK6@Q?3(zV?NBBDa4ma@Fz0=-|G4b6&N(-8D9&_sf`xPTZ8d z+#YGmYM)mZpO~`;h9fx!+WTnZ#eOuo-Kzv1sCj@nGcNM48!)=zAn_mbR= z^Z*U%dAzX9+@>fA?B8#kk7e-&$NVjhtDJpyz0f6rMFQb^c7g!O-;8$4vMYHKEQ;qW zufX^6K7s%2+f8xIM!?#&wQ z;1<>^ZlV`i<9i{5)dX2IU#R9nS z#3QIj+&@pAc=Y5F)^haM)g#P)AjR#K{$Zjy#fqdkA{`u~G_ABpp4pygnV8p~fH9b3 z`2Hk^GcLSqeeh21H91j^LCxIGn^KC@FXBJH)oKDcQCz+>sJW?Txz~+gRGo-A;6Ek7 z16H9Fe$ZJO-_%Li-l}Ne=UgqOVu8MQJ~94frx2U(j8MIgje6c$q5m+)2*iWQ^$ak6Hp`<-97i)6^Y_) zmjznYgiL;jAWr?1If~x!`G`%#1MPK%f46eX>o@2sv|oacK=(xKp?y}NlM?XVTr*E1^mxl0?ZGIbK~r=dHK#+E1^IWk7*zv)7cC6p@RA|0z2;1KuKgY5$7M$A?1T z1qjC=69j0Zk|j`5jT8ON#=r)K|B8mZ-4A!(@a>UrEUxS-ekv=jZToQm-=A;((o&0Z zp^WMR-ex^aNwzy9c*VtC!;UstfyG^3iuUNBYpbEF36gOLH3QC)%IYlh$D^`nznf^h zhLd^IXjvA`s&WG~U}T00w9yVks!O?j!$>2pu;A(F%(<$?JayO0D!nWK&GOI9G45^T z^C<#m5^qUmnw^qjA~@HxY}a#rbEN3(wPyc4V@gU*qyMoo-Ix)5P4_-k&Fm z>uhlRD!nz@ZgH?M2Ga-B=H85_MJ!XV+VwZl#uq~IuqMr~q3s;(ODdf4>0$cJzM*m( zuK&e9eBlPWY`?Is?mk48cBAlCELLvR8_P>R{e313`#dwVZrhdX*S~*t6?amK(e|Uk ztYDgN1k5$C>61N?!X_bjjJE|x<}4iRh*KAoY|%YzU{u0T$_Q4 z`6f*|EM9O20%&hGGH-xicD@nVgfg(KvJUrbR`XTdL60$DUAkz}CxCJ&zuY8+9|5nD zHlT#<_??x~gOTU6!Y9aowiTPpEbLEM$B`U7Pnzz%LZdTic{$`fYfUoulUubVbqGM= zA3xqQm@eL0@cJBtO&2LRwmeHl(_`Ym6r&%9#f??~OzyI%*T7no#EyxS z4Ye4lIk~VA{*2=pCJE;k2ixA#(n2-rUw3(S4E3-@j&)vp)keE&u90)@4u&E7<`zqC zwae??R4A1gA&~})?@=T+_N?yUV&+Mf;&EI3C5O7LJbMLCBVGEcvS^L{Ks0h228oinj?l^F7+Qbr=MCJj4Td% zc_Fd?+PDOP&H_W%){>JGgUVDN&Pwv)JOO=dHm$Tj*`Dv>JHbkZ*VvPTuD3j1YCq>T zLE97P^#M7^bX=xG1-Y1HBEicZDF!wEj}AwfOvd^;~krdKaIxR zQd;0YGqm(5ht-A0XoHg`559o)eiU3{Fhc9fus}K?fnaR#B8$mL%(e5qH9OB=I-y~N zZMn(BtnUDWmtv5{k_hy&a4g+^fuDrxEeZ<)a}Mymo}R1fqoKp`RG(R(1$9%%R5-!= zmlPT3g_^$7%sxd`daCw&7)4s`5qxaJ^c96^O~|>slkv?Tt8Nj3IMt(^BgCVk1)|=z z8$L63sOc92TiZIyuXdZo#XYsBZkRfp6{c@Ir^}!aS#BgkcK$aI?qPaLUq3i!{$!zQ zG%13mq=jRX1i@tThG5l%eE|*JG}|dsOg>tn{8EqSaQ&Q}`sg%jfZ|Xbi0Y;8;)@yA zEz4qfgCD5hNKCNhdNw!#`pbs(e!D~bBAYDxiNqbJfzoysh`aj+*MS*%=p^l|V0_R4 z(*9k1A9A|2{3*+f)S6S2ox*>rY6$-J*YxrB>Hzy8fAIBI)$`oC3Cu0JnnAMzzf>qk zbjE1EKO%p%?xHBzPlvHQ=CFk?dc>2iWiL3y(xUv9=c!aF6fEwHN>5~K*O_Kon`*dg zc^wi}eR(g8#Rha=s#YZ)>J<;gViEQHahswJ);n}Piw>h*A4u?z*x0Rpv9Q*ats`(# zUy6J+aMEx+1x)YLyVh<+(HqpViMd8~{EpK2Z&L4={%V)HdR)BoD;mR0>lQM<)tL_T z5GfLq1(Q{{&*#!>#q%pfkuhZ1R&pHc;fHIbhy}If^QSS0Y+b}`8j4@$VFEm^rvlxE z$u@<(e@`YvW*-aG(rv@A(s|Xb^Oyov@4Mv;jG7Ww8s_xDq%Uk06qK(Ma>EttwY8bv zoNN{yRJ=zN;l#GANwpWCaF`*Cd2^uZ@JBt$}kYS(t z6>7l!%BhDUDt>)c-sTiq!;RUzykZ3KSYi5WdGWwW#udl5=;PnYz#;;)ChG`8o|gNqR1~OU-SgAQSTS>Y z>vnO+@N=f7c-(Ts#z(g2JNYo*_mq8|y#U=P2S>uYjkQ}5Q#VE{6)Hf{yaZt;W7{t2xU?yQ2u)QU7r;*V0KD^ zLHz6t)~4f(hhH8KT|lMYp`D7GnDq4Z%d6<^KkKfEIV`qJqSCFY)ZAsS?sHK%%}|;% zrB&^;3UgrV(8hO+!86;X!Xx=5Ge0k@kc17?87NfUq%WwH(-9}|o!woXt z$uE_4*Lp&0;yGQSm%TmF_mF61K^Ei2j5E^Xc0uQ4+%aQ=ce&kjJ%Kcxll`5H7KTXa z3{VU#3n%)c!8TmA`l0iRJmMk%x7$umKaTG#E;vn{`Kt?KQE6UQWwY%y5|lcJ-c~TY zHjiIvgGv2E$7oAa%~7m<`%N9UJ*e|pNlvWfHn>-WAvk0;$Rsb!cs*!_0!+9m>1)N) z*o3vsU7-||@Xol-e|{cH1hDGRZ;ulKmfJ}_32W1by_l!dF3wSUputHU|Kp4l2$NY= zb{~pdtEfcfX&cY>%J*U-I_&YeR_V0{*BnSuJoW=*&wiY5<~x>`$w2%7!D&SNVfDd~ zwm56IiNdz2>ILmn;X6l^<&)atd(>uNy$u3^ZRb1?(+c@M#Byt77Zyu*GBpiDOBYXq zdDkaVPiOZ@)7J;X%XoNs18j163zC>rBKZ0)CC%{Ey?gVfn%z!>G7hRQ@>vm?i`?KV zdg-n^ea289h#fl;HvRhD^AV}9R_SJKdoC(2Rg){g=|syiINs&kOJyj6Yux-`26+d_ zf%JA*JzFNuw*v8!%B^tr>Vd#7@#=Fxh;pnj5caLS^kEOTR@)t_%wThGwJ&UosH_v} z^@rWC!1&jYSdK+Sf+`f*kVun{gx4cm_)Zrev+D@(UbhF49aG|UvIM3wH5 z4`kJB%blQK$Qx?DO6##J$Q~ujgRs=e=Wer-KEFF-suDw7R>qyiS=$)dHE3nKp#A6{ zniPaiCP@qOJeC$D{B(oSaP@gTQtE%u*Krr>p-$GcC262tNiv5Yl@R^{i`^MQO5Rc zUFXKf@(nUkVVARVOBJ$v`emDFT2qJT8R4!!4}-zbz)rtIl7a-ubp#tik+QBfzsDOE zbDA%LW!J?#{uw5!J-s`E4<_TVJ*N_9=fms27wl&KwXr`AJk0hTo$VTY9Hxczz!tUZ zUMO)$8C8d3WM4q=?fygMbhEZU14glVzihZkj961Qy3M=^GeN zdlLmnPGGR*4$rq5+jJxb^^&Lk^FM1C;<7)xhOIT>i0fNrhJp{#Ld*>*gCF&79g+9N zZiP7_EGI1DBKCMM^K1@ZOWhyH`g<9}F!?XmCgQX}Sc196n$uXn5HF^j{>&FS@wn0Mpex`2jSM?nj=?pF5lH znr=_5+*XM!EQ>>Kl(~XkE`y8K&86C?i#~|!C4KGh%q2`NjuU47Qi2yfL*4aQpHu%e zCJl&43cXAp9X|v}c?Ai4P-{iFq<%&R?u+RnZCIE~vJ}1nHN^n_jLlOL|cgVy>UkQcjeotTsvY4P0RT&^D~@I&#Qze|9qD&(s`3 z5-&)z?G?~kLlQx?7GLvapM)2Mh>1Qn~8(zk2zn>J{I#hE@q!`Z)no5 z;$L9)M$X0TC|B^C_C+>>C-2kY2D}MVIR-YG0Ym{(_D24uCawlE3y{{{!3?|ebz6#C zd!5dS2OGj{a%vqC^K^8b#O?f27-U`ia+m1M5qr^llO%Zo{%G;pxM9Nyd$={c6%cM? zW^jm{+g!*0`s>fc3v#zy7?1RUAoJ8mRWqG1N(j*1k^NgIQ^ipd^|A)8#f{wKBDnbl+dQLz^Xy;*6P2yRxOQ{wfaN+EPX;;rQwJuYH zYzz0-snV6clW*7IKXW9z3N@+{$DC$-jQo20aF%`#^6yt(Q|?VkyoBbKOVc*pFZ8?V zet?m7^6LFDrJszfu0G~yqa z6DHNuz&AskY-g=W$~|TCWUBF>$M#3-(N3!$d!%-4anhyiwE}`Mzogb%(zmVAJs41d z?-M)+&QRv(pUec0%mgSdS32oX3( z*7<${qhJ%o`{Y}G?~_MY_ktWNqou_?$jgcbd%vY;Q+acvm)&#g&bB`Kw_Em!mRVm^b76ypIz^dab@4??}F{s>KECD zlv?Pf_&}q*f&}n=jvg5$p)*##2FI!!S#o#9UTH{S!-3uT)%=q1A6H_I8ugSM{7Da0 zyl02p&W&`Zlm$VX|(JG>;DY|6B%r7^C?+j~ny+ z;|shaf97gv;`&^a<$|tGT8oMNZ`0KcX`uFSnC*vWV%?_9|En#a@dx<8Up4dYYV*Re z(u_9qLc$v4f=PXZosaPeX(0+>G@EY}HhM@nolY@7KHHVO7RS>lBv9X9vCr~3CPD&MV)8!Y~hzmJ8<=ws-#V@pmnOiczGROQU_&Z zAO#$Vl@8h|?2LvbdPV~TfgHn#LDZB~Ao4xRaZZHoSnCl>6s1;{`Vl`xnSY9 zD2J%6F_?YrNHgax&xBFJG5MOXM&iU&7h@LftOc6BTlG#Z38T{OfAK#GFVc^uKD*CyLjRfqU8Y@*`{0 zWtMg~M0>t=^9Iwp#GaxL%$iT+#Mjd`^w^FQY(s{c(L~=9A>R#7jx9ZY|F>P?@QKW- zGo0QOek$#i6ERlkW|Z2HH6GaB{s>$wxh&3yl-`GZQD~v)7M+~%3*_6ab9)HpH<#E2 z1>Vm_0Qey)@3EfBkAsu_s}Cnd-4SJScAIAJR>(m;_@eV%sOL`5hU>~cJcY~7q`erS-U8uakEsew(3uzKt z-8PKjc_t;B+jXBk!dC4@knbO6%)>ILw|)Hl^!c=LGR?kW1G}HPHEQRjnnlOfXGFgF zt|B4HM=(s56?}4Bvu-nf0|RY1d}2REf->;=DXWVMX>bjFuhs7b@CDSLN4~r^FB{0H zNP(y%;08Q9qf_G>5wuH$_Gw03nQ#gjMbi9nILm8zM`?#(k#;5G7m|XXrt&Hc<#w#k zZvNsn+;z5=;(*8V%BEHz8mgx>C((mr9p5)?V0b4dWK__&bSr+_E8_r$6IIw$Sn8{bOUqiiGw(oLmf*yJgp z62+^0hztigdffVa=L39*Zw}@R|Dj_9VtEbY(`qpwE8m5f*dlFJ!EMyeUJZFd^xDu3 zj%jX>q++p8%&~y7eaF;7G=#0;H|c#g$EK4Au=z?7t`NhAPaSPc;_Y@*mC5PS?G*Dc z5z^*P^=lHeZ&2QFxpY+4uA@UqgUi-H_=OZ*P#2fD?L*S0k2R?z)L^G=pbx3;WOd>l z{;W);kL^UOyFbyFf>$h|}11kvB_UZHTZF*u5D z&}jjdfvqN2gNQw0d*Y@|y?#ecI;)4yaewBx>LHzC?U5b;8;0?lrG59PBD;1upA~35 zJw{@OLPoWia_&ZIidfd%D&N=k&nku@9Nwe)&nlMlGO9eh=I!^T4SO3Rwly>rSy}}Y zx`F`^d&P=S2q&M6ljRFZxYOLn{;;<6Fusk}bM+x`vlath(={V% zy_k7h-vs~+&eLJXZMi3uqyn)iQr7PJ!t2e%C-ECpZpxE-P8IY=kA8`1yPlmG^Ofml zW^p;|pJh@*IqP!r_ZdAvg}eOG_h8j|=V>9sMWQ^3Q}}^}tSY0p3le5K$})q@BIC^# z+jM+0fU*F0gad`*LI~8q9QdVEG0@ zMKw>z4t&0d9-bD9*Y@*yw{v`}TZ{U|F7VCS6I^QWDeqo|{;}zp=ImrA#6!VE%P#y~ zOz4D)ME@U$fi(@Yu0!f@qkfh}gxw3~$W_A-X~-IDBT&fX^h7EMUo4hIu8!V6!LJ(&ccma~5k(m-}~1Kv=P2bhN;T zunl2KnNYmB+iAZ1RswUpq#54JP^I&#kWA`x0tIhI$+#Aze3mfa`>r(*Zq$!B0t~yZ zWbUp%%dYROkZ@D&G+A-&74x(xuz`TuhN~oPUBt;;r}7I=h^AQvTQd@A*9!PD4SY8X zFP$61(S`~%eU0yTb`51^YM1`&z;hcZ=`VXG&*5AJL|q3$dUFY}M|~hwFF3X%2yZ$z zEkPLdUygws=Ixq%DXZ138Mb_d`c`Bsr;_iFj}_bBgH~Ru#3-JAS|amFr(e~zKJPm%o@lw0l2A#wW`r`J>OKIFzvq4zX8Y_e?6$l;FdN_Hd$}=`J&2r z$;-}ovoSnFukp|&^gX6lv&kulM3Jz%8^K%A32%RXZ4uPgj<=ogqln(qqwsgDr}$;t zK!J`_KuPIW8G&74FSt^u2~?MYRu~k@aK$ zzbJCe)ewiO2SLi~p~IWZCQdi3j&=AG*RUEg`;`gRck_RmD<%kAD4Q)Vrb?jiE!P&a zJr>^7cQVVuznc1o{E;IV$LyMD`NN9b)25qcXd<)hn1X0acA9#7sSOz?dukSKoL_y( zuawgMTyq0sPT(VzH&FTxv>^u%y48@*H@#~YKWowdr}-T3uaqt9Lg(O*=XGMWM^8>4 zfg;?HRra5=!b^X)<>|JA>r!k$IA*ns@MlB!FZ`v05}x9GuY+?8uhVm*W<3D1f!7o! z*DWSdyqUC9q8bhMcli{VhvY9YvU*RpRLn|R(bQip8SH&(6vl1{A8E@9E1^=Vt_8K7 zi|M^8)v*5!d$de(E3=7s@z{Z-z@4?OXR zg_69-2CbO78F4;p?k^NVS*G=v!con2A$};JBAl|QUal#_1&QAuCXI#}Z&pFvd~Nhe z?cV&S)SW*jIg4MoQnc$VJxrdVZ<*8S!#*8HeIIFi=C&adw$o0%?KIbK7>Nxs3mYe) z(f3rr#W*db6c+?hVKQl5$G|Lt%{7t`*_CU_b)7STx72AssB#SpSjnZ&s@vE8qZ6!9 zG!L5~ouAr1Oc5tN4gx#M3EFj^`H}F)@p_9{DH@DogGZr)Kjx!R!}YpDhU;TiC%NxI z{?|V|6qGjtI|$;-kL}oR^;|pT&l5_tZ(($>d@0&NL+mE-C3vzi2G@_DGw=sGRG12h z-2n!K{ShlKvP($lz)V8qBrJb{NBxfIAFgF4eJ9_-Z2#mgO?H(Gc!f_qX=CB%brUeO zclfTJuH<rb|KxzoYGMVe=e#Qi}6d?6x;D;}G zLu=QhK1)di5}3~h9S(aLTT8!xPMZ(MBqsDV1WSNwYm6E2yH}WShnntj`8AukZ+uKu zDDIbTNx>5I?roExcrA^5S!J$&bs#&rxmR?^pCW<3d2E9NkO?V8vhurj?mQk{Oxa)3 z5BTZ3*zkNERDZIVXGsV~Ct0Mc>o1t{jc;`SpOwiY|6?!M_;0;n_j5#n)z4l~g53)S zzaVz^8;*V3dBdV$e0o}KCP%qm=JxE91m1^K2+Ca+~AxrW4=oZ*t$?ra|$~ChQ0*@ z;v|h@5dKU?VHmYDRQod)OeU=l!yK4JQ~LN^=P*&&38nMeu}!M&AyYKWk1>zG;E)+m z$dxixv^fPmz`Z3duR9DkB~hZuV}&-f>d3c>Q&2qnG8tGdWftI>w*9mVwpdqOUSc|t zO#v+Ex2gZMLD!n^Rj2>;_MFpqo<__a8-bYkE)pu=((%&!8Wu^L#a}q>xrU$we6V4M zDcl$4WXwYU^KDv!=W`}ZBtmir%K(^|7&;8ka_;E>p%5vR31_`nbVyCv2D8K3S zjB$Qo<7HYy7EzNfW`&ikiKc89C8wKjZ9E#=?pD*8uVt?X%@3c3M4rT(a{MgE>p;rf;^PzQ*An>&hBPwowI@a*J z9l@;H?_wBf7a8z|W6`=FL+&RShx(9g$#c)|O3XgL`(+hnTh!Hged)u)sC0723#YS# zBx|)WliG@wf@4&21SI*?3q3s)g(yyEJxjqj6U&19EGj#mw9JY3nI8L5p!x${{bD%{ z*Q$U+{jw8;!HDF5l|TgV$IG`>4cAW!bL#m*V#K7RoXZpQ z3trGVt8uDJSPo@z{>OA3_+O^$CvTfJL@U}{d)U?mVe+dm?p-iMO{87dd!&4+&GunM z)Y|H1lT!@$xCl>@i&>GJVc~>aL;GnV&CJLqj^IfN!r-sv3a`p%-*gIdPQF-zWUs>B zeVF|CmkDs*z-CV-O(M;pdyX(Xfae-6wJVs|qBvQdUQ_(vMr=~vgtOTbM15Aso-3YP zNi%x7;ZElLi9U=P^%d-x@@0scc`sE-w^w%T{2IT%U4Sk+dsQkSyAZ3uUoNzMKrYt@vc2s9(gWe{e$ebpI!J zqmRD?u?gq}&@jHg?}u#nqf1=s$E|S*HU;BA{BFDj-m&4Nq~;I(x9K6hc^SyT2~GsK8QWF_(W@rQ;YMGP|wkdplZgl zyk6Q|&6#ewj3OzYzD` zT)+6SBnX?K>C#cX?|jKO{17(iqPH8HwTUpvw#GrkRaB2<@nz$RJOdARc~9P{+kwADn&kE+44?IxFk@Vy!UnEs+vDvY|6k#lL2EcBA3OvwFUFfM zDeG!-$$5zBu+C=upVeDy`h*;%_auAH4~zQ#1&(2Ql3AGMes=DNdz#JL3F5)t(^*ds z?st^)y==rfs0%y1o_E?LOQ-s=0V2bn=3-KGlvJ79ho@XUOw4=$B8^CBU_bm%4Q#{T z4Xn5(cWQ6~FKzCKrm;IkAdo$^k6j8ooKv}}VM<~b+wXXE-@gv}W2FA%8eeiTTjk=) z$wn|AgZdb6dRFd7%->{6-L^;e*tWM%c}G$VcFE@?gLu2OHF-(ye0 zrf!6Pg%s|4&D+kVBlMG+%9gLMU#yUl6bWhMxEiskTbchM^@}b@D9`rEq?LY$E!xzU zn>yR{LQ}(enlD4)vPYdieCW^<1vELp0mn`>QjxF<$geqym~w#3<}B$SxTXo(K=_eh ztLZ8`g9~IC-lTVeDoyu|!}gKROZ`AW_UG9vJa;*8tLEtEBFPU$#d0Xr#fe?U8tddr zVc_E)svwNiud_w(E-8Zx%i_I9++z97S`R8eJ0LhMBrs%yBVIE)2r2!fC!)H@;AP1| z6m2T!zx1?b_Mm%9oiNw8-(?O0%rM2B3RUndgCXjIyzq8~#F2xRDnp8Hdn!xHrz(O+n5V8H-$_ARGz?&LG4 zE(1)4ok&BJrkT#hTrVu%0URsMoSKk>*=C~o%2WCN*I{9vA;{Rdl}?*TDr+|3wiVFn z{UEA?uif#x>bY0q*j`-+PoavY+KN1@N>wZCmwz5@pmn;umAgwDt6a7Ig$201T_*6A;yYEIy~En7`c7Oo#m z!*W}qpV%WFT=Kk;FyQK*RWD3)77eUrJtUcK8$OxvI|=h3ynNHJpF}){RaD6vFr^;C z@GBAj%yx+D!gyQ~&{I#7E3lePycBkPza3+wG0wOueAj6)L%L`qR;#l>m9XRVkKI!Z z4sEnt>pNogAjv7?=#n2Ft4}rhqQDv!&=srV1Pd;Iewip)MzJsFy8uali9KHAf9$4i ziVVfJj@}Ng=dzj&F}UI>-OZ5C_vUtQ%4pNk#I{{B*ef6B)Te{kkO!Mgt9iKqXx1lV z%GlN1aJ8Cih|Ig%2i~@E4vYNPu6cD6r4ih`r?MidQg6cZZteKv@NB$|xJj7FE~S%& zoNNsoDtNT|5*rF9Mb{}qY2Zl@!pbm_U z!|3@~?TsTp@Ca^(Z4&9+asNbHGrZv#8;>Zze6-}pN-8&m(9z`0{Xg{2cJv9wzw7yl zcmMl(?yY|DFg@$~iwB|s+Wu401S~XlCy}KvjF-Hl zAs8ZhF2C6A{8?ucnR)NKo#zCsAjvvuW4B{YZqkA0MrK7vcZ>@W+)!*pANWU7Os%Y3 z+m~6OHiPIB3O9a(6+?pH>9VquLhl5q*GKZ?=XH}yT)}%8cPea~Yf2D6T`in&(Rf|- zR%`x#njS?Ug6@to0cfLy_`XRtt6YD(JB9yBKBjg>3*1#?AN;`J#}I&>Yw&?3r0uDr z7g^iM{~#AUJ=k5}u?FWdt>5zhPi?hC@4Z+gp!?2d7NGb*OvE3M6xl{qcO)1m9z0Mi zie#SKq$dmpkZB=jA{m=9Z2BL5GhJ_MGeD`-oj9mlos@XzWhH#)*Wv3&2w!gCx|6fd zHvZN>K?{u*-OfjD`yD`B5xZPV-(ah`ZqjJ-3t$!jMLPW51S@D8D6iA( z=LJ$@S6A>EhZ98Y4@JRKHcXz94r$~<6uJsQZ&*JmT`l z-&3>RHw~?}-s4q2TW?@tYxz?CdXlDnD(Z4(hokO)`mVhoEoQ>ooaW!r9h&v0MGR1o-8?_DnYRNDlsp2OX5=GY5EKi1ouHH8bZ2 z0Zdmf>auU)gNL%_Zj@d1vElJA*pvln9ee4AMW|R@&-bVc*ABiok)(~VO4RhsU(!XT zXq{<&@H{$Q|I?s&pQ}(2vU`Q5ARc!BdTxzhuBS))Na=dtns>QF4tbR)Z9XBVt}Bk& z*0sl@-j#HG!zJ97WX(sqBU_&kukN5PXPGQdTsxBD`)h8@;yC8AU+9_9+}Zul1#tYc zkHpG}%!M=FnW26d3SG~+Z?D@9%VQt)s<+dbaq=KKbM)Mc$&cAEyntBty|{w5L$b_p z`5`;V#6?(+C-v$IDM(822tU36M8Y*4rn~c#mg}@#uIB0~Mu{`WCa3@*1wL|9;HStJ;-8QR5Uvs7Crz0@gxvck31r*MgWI6gR-U{@{Pak)6 zW_|$zT5v*HGm@H}*#5`ZbO%|TYjsgKO-8Sh5dO8|t4rtL11p+Bj;ANs2Em%Fm_Y5a z2ingHWOCVS#1&0OEiRa^B2hf?v6bDvms0KS zF;$p!qcz~+y4zYVG2M(2>#>K?W8Z#a7~0g+UK2&!2VhI9J!M4SsEmE>QEHJ_&1d5 zvmi0_t1JxA(WburN6ptk1Sh{7-C6=nhj+d|krWrNwH4k(zfZz;lF=G+Aa*}zUj5H# ztvyZlJkU2PYzC1|Fgx%9^-6CblGppcTuf1JGoak%W0N-S|ntWr$q6U z@;i38r4z*GcJee!WhW!nr8t28zA(Xm_>s~TZqxMvQ=5O6&g1ir(*5^4V8?&C13Vrk z_{rPU#M8b|3N)-sZT|eoB(S;2X|8W!C{&5q0 z{g0a{-E+L%et+<-{sqB^b_;N#}s!}k!|*X zWe?u(PVo1+)p9)_qXR9$4TGy}IOoT8zz31`?CZc4t^?nHzYZQuiV>>C+2}QN;ZtwF zw`Bd{%y(kq#BrZPE&PQ^BMoAnZh&>0QwqnAPB5oC3-{z`4+*uEUhBP5KOr#>8B^Oo zddwR#1r$7}wZIZEXpcTPB3N7AH1-pTnf96>XR;WztD}JZ|8^9}{xJ$%4$?k9;c3dC z@kjWLgUiCQ4yGS~?gLcDUg~rZKpbj$EnF$Ry05Ra?-$rpg+6&x?DH+Soi8vTMbkK> zbHSiDNc?vy1c%g%iHZ1zgX)$2=;2Y%G?z{9+2b=1E$L)yAdc9Q- zg-^-j`rO5a#c%y?;gKrio4!=Z>ry_vy{(?DV;?Se9gRi03D(>0O)&8}cg0_eIe-X~ zpr<9ccbtPyic8-)HA`Rv$|t*0acHImw?6;%8t%Bea&_FmC{KJrsF6}RwN({W-h*9Na! zBWjCFq$}rl5?P&3@~%<3w&K1gx}v^~#yXl|`rqNoUR`e7Dex|7u`5mNtJmNoDg948 zok#vxX@4D5h1<6O!b&$tcZjrHbtnhb0iPp{no8hJvGJbFi}v?gGVt>VF?-kNVqRrI z4dZ91X><=|1^@q5YE$2%atUN=2RYyTP~0s+yV`F0TO~Sr|9`85&%dk01J?Xl^ZgMd zHyPTn+#v7%GZgTjv4OKF<0V;nb

_|B-XJjq2q&dgl11{*O{kW;AQ|o4DxrQ;GSt z%%mJ_<%dtyB)WeYdHeDm2)}9(-O8)uwPe74QUlm=3z^Tg){F?mW32_j8SzkJufb0W zk>9-PLox(w_^J!{z?%{HtiK{_nG#A_>(1fGzvZz?kF0{#Q~Bh!!s%Yya83bUS9yN$ zo3@Jae@WMv>2DgoNd;5emX?F-I#@ssqL>t0YEJ&6Tg$jSYpzM`D)d7G4q?a?rzjv& zG);Z~m#Tv&@9)BrzhpDy{5GWb<9{zKkpa|}+An+huciaNHSXW@b#lWgKv?;HjShbv z+MTNc1#3*$1>StW%cYjuKP^J?u;1Mk+h0Xn<-cq<|7?{;cLtBxCSgL>pj^!Ve<>I4 zl2xLX=GOkVGNw(#|JHsyy1Ul=m-Yjr+{^@MKg1B}`tZRZ2uwLNU-Z1s#*-x5__YtV z@Ou)lg-h=lIYs)Giu15>qo_n1GneNPAgJ^pUFs>I54~D@96vSVq&Fprq z{4)#SY&~FS$`jQ$t7v);gbY^#>895h?d4HoZ?F89&yFGwX@otPujVEvlW!^iGKt}U z42g`Ln)h&PGx6!YAApI!0{_CKB!K4r1oYVwKPkmw5Bne*sDAKJC-2(UF9}9Jx6)C) zM$K;MHdAQ|ck`_>UcNu~UUKQ-gk{aPAL#+@i8$c*wa8Oj`2TE}y@ye(G*6^#BhvUd zpF$a$QqLkc%iK*WXnOu42qj*PBcdetl%63xM)wCH!IkhMf49E*n zSb@sQX_^3EJJH>%?8Voo&%_VyNCqV)e=DBLCi429F3O(PJ>(n*Xw)h#GlEzIyX^ta zU&E)R;_$i1--<^c?)*NABMhoQ!TakpIRXI32jFQi4DYfv9vlMH#sy$hm&J9QM2xW; zoa9Fim3+J?0{&D2`Md7MwwHB)S#~4ATNSXdu)GK}T4-8<3k09JwKMuA-rpauJogXU z{ajmL>o#K;XL^6Ck}SjFOFAh4nd%omFDMZJ&iQSUw*0|b2`JIant)3H5((Py*-~oX zVh^qi=KQz<`!*^(X~v0Zb~7)q3<&Ftm=6;EzY)yzT<>nWP%+BPV_qY$8fD=TYHiTB z5wZ{}m)}1LsNbrXe)=@cEf66zTKdl)eWQX1iKo+rvojNwv)Wo=c)n!I&Rm@|y0rIq zBu>7h^sox=oGQVpg9e)y?xV|0Om6}uu1@AgGTqOYdHk)%Mx1AiR&JKPQE^l~0-=w5 zWlHp=HF)0)>>JO(b*Q|K>PCec;OKU0Z z-P;BJCc|$f1vEK<=W`+GbgJj-BJ38Zp3A-p7Y#bCQn>|I!)a=tTC%DnO$yVHH%@^q zq4y&}|6_84p0F*p3j)5kzceLepj4f{8WLiQ{UuhBc(F?wRZ4J#UI12ba35lcA%fvh z%{x4X3Lq5R^EK1!G_YD{&lM?n``c9x`C+M|S@1`b7}JApuT0SK?=Kouxr$di;Zvoy z2^u*lCB8c|bzi<{rt>J)UTTh`;|AUrXd{TtdPCe>b`xRTHN#m!sAI?^h;pSoovG$T zJk?D zjDx(Bq_Q(6G^&N*Ao;@fEBDcqBP$}TtgL)omVK-L{E2-0xMXv4(>xXvDzHxVeO60d z9r}pWl;FrycS8r&Bx<+lY|PoQrQzVSR7GSX_8U#I+_Dkt<1Z7!;+a#?sguk`x9FF~W`k42|Q;q1opAu0+*MN2=iIC+vX z53ib&onN0CnkzO$3UPyVH-;(qo$t<2;I_FoRr|YslAwNwZuVeAXUuM*x}qqiXF25y zvN9?tjeQk8ZGAl*RYzhi@d!Fm@yDkhy;6qC*-h}oJxkp1CLW~)Z+iX^A?S~innw9$ zUfwqxQ|zz$)dml#fVk`Y=BL2Qj{dg_O2toZ^2?t)p|y>Dc7mt%-s7J8iLXEJWpe$L znk4hr)H})s5FiX{PQ$vCW8#r9XA!r}u#-}Jhduqsnyl6@PD|GxKW>HSY+&NP$%OAG z*|PwX9n@yr)6CQqVn0oO{|%&pnl`?DLP=P@$Y!X87qhYx%@ebu}-Ru6ovmA`qs5@-nD!Y`277uYofryiY}fmAP3q&$cI04JLa%IG!Z1{gs*e#D|24 zs7oqOyq!rs;1*;c^(UVS3xj2{2h~#0jY)`q$hY(~r^$zD%Lq)4frkwmo6fGG)Ji5b zWdq_)cR>%^X?4ZPm?MZk*X=mL9pJ}=T%=sj2!FL2rff%Rx1YA3M+P-PoEiW`3FZm! zwuU)5(b$EV?E^)CF|IQr!1fC)kvBhoH0LH*ckA3|(#ZfbAA9{ffFXp>(`H9QDEX*_ z>&@C*WIq&sli_nuH^_mrOGx|c>tOV^H@VItjw^FHHKW*SBNriilC*sPfnEWuPl_t`bwfn6lO&d_wI2z)?8w7{Efgo)e5Y#?a3!Aiav&?P z06)>1S@3#Hzpk{?UBF_qS&!P9BpabhdT2-Rw4TYAjiqMSvp7za!*8%&<`?#%m4~y( zMwej^;+LyClFn6eqi#+!C=^iO0~L_}?;P(l*vF4@f`>x8#gVs@Ydtip-h|h9JKPvp+kHvFp+VvP zDP}$v@hx ztVMHQY)O1Hl^Q^5bbc7K$qVFoA5DQnFE#r_wF7X5q(nzY#aoh&KBrrogH6M7boxHM zPg^j&^2X;Hgh?hOjJrMMRApM%{LNf|-DuXaPaSkgr|13U!gHfvqWtOW*_tI>3DLBY zk=#4hqx!{qyR(50mIr42qP)*r(Tx-UI)2S_s(L}MX^9^Sg9B9sz{-8Q?wBth0pam6 z{>q*tvMUNlOj*3;6(6>@x4S#q{lFg#fuPW*^_bV2$tEGEz8eW0;lxXy(@iUq8s4CK z^IG=B-P-ggP$b;cX}<->1y@~xTxll1quY`n4LZVB$HNVcU|~;J`%}l?MM>f~j>d%P zqUBuPN3F1qhzNZwQcWv8arf=#2ih*7#kF}lMM~f5yjU)8Dqp6We+|cozka;~hgNRw z6juJZPL^4D!mO&iF^n??J^3yWlu+WE07NWBP&Hx2#B9Zuil6 zgoebOE)C$sb>&{&p1s=N0Bg20>0-7w8INabJouZ_p`V{;b#2n*9nGwg^X`>lVZ&LsnyBVuDf?5}{VyuA28NWG?F>3- z>q77g@l`zZka3i?Y^Nu$8}g48&Ay=LgxLRaal9s}FQ@aAtl)XOVyY$+wnY<&MPotT z9$SQ;CWkKcq&?}iVS%)C5;tz>mh(9Nn9%QoL@I)uP=13@zWYu+!{*gcOazwef>3k{ zGj8mJ*9tTrZ;mMLr}fQxT2P+9D-SpQfW2Y2Q|*D$Ec%@I&>2zLw3X}gOSTq_)$%?+ z)H_iZdmnQY?3Rr<&LNrFJ@7skv3U0KeMZ);U$jJbOUh~9)HU+cEk{hnS1vJWZ4^e% zmG2k8nBG%cma;QbxOvd5tIG;|frWbZo1{mli-I#na#dEekam;%Ckz&7L7o1wI7uLY zP4fj;SJ6`bXg-ZI=~Jixl^I(^tt5)=xJQwel9JLdH`7YV$n5MN(&Ed{A@Ms2lTAc@ z6jiQ|ky+!m3+}3q=m5Qrkeo{22Fm$-KBV5xeVK387~6zck9KKenC^0M?-MI0NE@qL z#XM)?V13FO(i|6V8Os}exYVAemF!(=GnSjCaiv}e%zUgg#!q!;iG;n{*7s{WLhc_6 z+!GQSBOKNT-eBsA^4fd2^(X36dmAG%6sOnKy|_N=^p^m-GnDa8 z3cYPk?=|5ot1Cl)`~0dnl(eMp)Qo)jTjr?H8GdSAE5zqSvfRhi>^Fs0?mipjS6jb)aP< z?UXy~p%uP~POYh!>zIY_6$ywfj&gcnlKB4kEG5k;f-ehKoH?fAI7{pXTW}XXYc|{Q z;8`(IW!V*a@rlo29$ZQp(84Rw=}fpkUz3(>bh!3Ydpu4n1E#9Vrwm`@srMf}^`O%K z$}FQ>IZmVH>9NtLcG9oEujY!WbthA1q&O*4UUuoWKNG&Y3eMepl5L%)B9%nRMQPT> zE(MOt3SA0bsUpJDod~{pGW#MC(*9c0c8(mY&sJiB%pB?&Cnj!6sM){Voo~*z*-x+| zyBvS+=C*(&QjU6Q(Ch}bwa9)8xh_%lvEC(!gyW;bbGQ9a#X4k0s3*V zXsyRlWsevt8Fvf-!Id5fl)gz+3z8`%;JiraMhaB+r|to zgg8wdE|^7U@(FHjA1dPQ;a0!O6S0Mk`T7~om6nkDJzVQglj1VkotVrY?nf-y(xvG{ z>GeI5D~)Q7eQsb7%aL=tPSW&;`w{Ltj}h~1ysQKCCl&rsQgU7fPhj~t+n{+EAQWX4 z5Fnv;wJ#V4%`=pJn^6Qi`3|c@2aY%{lK`^cHh=%#_b_nP!tpp-!J_(q+VyLrjoM@)%kmM(rM~Np89^#s5y2etNgS zDcDZ^XtdsD?08=Tj>Ojq+vNfH+}g!>4oT`_?{LOwKKtUws`Io}O+*MLHPU_SM>UcVdLAYlQmrP!g4uxM?C+x8i4>F>&%j#Lm`1a;rO&0cM z%0w;_ToWA@x-T}5UoK5dRL`0SNcye^VQ%!@31iRa)P_HjBN6@);gqL=mfTEDeY2cv zrkA+oq3q=J37Y-QrbA1+PSmJ+qW;qeZ{DeA*E@1r_{LAZ9^p1`6+9%V|M^jjKx>RY z^<^)SEhIRa`xX_82*mCm<&Z>NRy)Bq+^1!!+DZ~Veynph?_p7cle)G-Dh#F7E26(F zq#-T%*0S~#vgWRO09fw3GzOIy@yBfe?{#3E} z!f!|OHFAqiY2tB*1TGG>kNJ<&Ew&yGDI#Li7++ma5r(PSk0@zDh{I7QX78`@kHh(+`*(-<($@zWzY47%E6ubQ{({#o9sT1DH0mRD|aH zz>B4@+V)1y6dpp(v_7W1gUGsW4U;OQT_>C=#By~~bpP`dD#7=^`sV6)?P@#j$wfV{ zE#8Soq4elln97@UMuo`V^lkwBq9Fvi}>g$sH-P==9Y!^_8TxK4GCoa`)EP zUk{gp7(z_7q?c@AC0bfqj;(Va=+P~s{z{%9r$sby$a?Is?pB)CP9klvsi~8aQuk@_ z<;e}g2TPs)i=cuLOTOvJF(E=Kh#_A49Nme%dOO5?6R~%geFs{jO-9XgT>=G{o>NfL z7mE7%=;aq@KM(V(&Kp*o10Nt~Dyaw&>4Fe<_sYC^*`ICaLo7*1vuttyyq=bnzt+%f_qMr$gjtBc?V_J_dXlF7MmW>FHkG#i*XZps9gac}-G3p8PiOLI|yUg|e1 zyjJZ)iv6m$K-!CNB_+IW|{FO8t9FMFjE336{kD!2!=ED1$0 zsyZzW8nAv}DyIYwHowB(BVf^1D8PAp&}zl-lkc=CgLca~hV-Pa z?Wp2p3^V}m`semff}Un@^k1wTdH^piEHMs^k|IJa&pIf z_EXFf9ft!SaJ%!ARn2R#p1Y=|r|mQV@3-E$>$YhsQ7PByl$KfoNz`mnekDc;^ZyRSWBYrC;rpYw%? zItT%vlukd4*o{d~&BnGsDU5(5t7CZ6C{!EnEM>0aWkGxH;QIoq*_R%+)E9?EQx44C z)6yAy2{aE#4^B}yB*^^F|FAD{%$rLh7AM|NZAs}O`yxrpI=u5Uw3;mW3CO-Yy-cc3 z?ftKnNR>Oa_)?qmeAdZ?E4$zk0M;UQI>0eo1wfwi=7j+YS}S{&PBoRJdHM{tg=d1TYG5G8*w zNU*;po<@P=N#SDV!=)lSp%y2r{`2+de%bremA|0{VS0UtaO6{S+OPTf?}(ScmO>=e zg?aukQN#&*bE-Bb5?cf7<_fP`yDic>Fpb*W*b)wOuxmIT3GX!d zS*_u>bC9L7{Yv}qV8Y*9ZM(saQQVzfUct*SMEOf)(!V++83 z?=F&|V7b?}RA8!&Z}1qvkW(c~d!QIEoe<2N$Ja+HYmX`(D#dUn$9aC2d_vjWq=W}R zYfN6j9Z?_4;E_)DD6*ZTwzV0PwodLo#yO~`tHR6AU&SX!B$QeV-E9Wp<_Tq= zriskAaz$+W)IQmEkk4MgU&RSn_JylA`I?8&R3VI(}gGS zg?9>MAvZd@vzviqe({qt1=P1 zZ#p(Dy?FZz3KgXts51O^G|Y*+-%Eri#=7)~_tCf|Z09|8+WWJw{fwO<=U3wm4mQ*q z6n5iBrex+_N!SeHtg=;!!^MmZvHc*8FkqS@#>jWwhBSX8{qt~M2Uo0+i z{W-8A$vch4!Ff{lMI=kuvqf1@@sg`sFr2(K&meivs*W0Ii|fnaCx@5-5?^2DA367KxDn#itPDKd))CE>P7=&G&ptWrIS=9v zQMW{+Mby01Ophlq^`Tpin|W-mM}bf8eS|=CJ!cb>n{(V#EH3vwEc4xd`V)F;&6mo` zX{hRtOF@0fGlbN+Zj^X0D}~bpTrBz0`gC>yJiU<1s)lN2L5TB0qnL+Gc`XAS1MiUW zM83Mu9sI$%#d~KTHuGBc!qZD#t2H%xj-<%4*@4Zyr zgoE`nzV`3pcm_T0A&wJL7W}X;EfGr8*{Og@+?FH&zuX{r)i@#!pPH1MY`r^wb?Hs_ zDTt<=@SVWhEuW^4Em;Ca(Z_eG;vaml)k@Q~VDv-m=;gs$-m2%}WvFf)McJEe@lSUb zvhP5dyZrD#K%}s_H_-VW!g1kXDG7lxuZmb^S_BN=3oU zLBuQIM~4&nI>=cjds&G~Bi`-50VIxM*JY08#zrlAA_q!^khbE1XU6k_X~Bkunc^j} z$kJk8PR2cTvkJ}^V@FY3Jb54@xm2DICkK(1a|;PwWJ!d z3kG_;%MU(o~7CR|qogWtgGZ%4ST!y|3@HV|t(V zm%0Jy$MlmiApDimNR9F_Ka!Lp1+8T_O}$43UZnNAp#0)D5vQ9yxJ`_I*y-+cKjF2o zg_H<6=(-yksBi^tZvDbr+e?mXh#x-w#q%zfXs>G#sp`oD5n)_8TL-?kBi^Rky@*0$ z_;c0k`3~2mq&zf-ne`ah<%UM5hMk-aXOY+9G~O{t@Wa_wl9kdul-uR$YmdpAXh13Z zX-&>6h;vU-jZN3P6gH!87MSpYmYq#;O|A*Vum)lgP>j60Q4az0&4^JiSn50RB-9eG zV!oPA%b4Ak9fY5YyuG2Ym(^}5JlBbfG$_qmlChsLCoJ%F=)Q9>qn{rw?dN{iDv}Rb z!YgruT48GBDB(}}o*%HVv0|*m3%hOJB~q*wBw_5-6toj}n-R1Sbv89SJeG4JdsXk| zGn>Ks!Ee&De5cd&T^X7O6*4k1mw$b5#7Z3lZyX9+){Rbszd`El`E9hn{zeUIVXFC} z3pTVEV}_%kCHaU0TG50we- z4_CQ56TOx7gT5Zh4}Qj38~IC!V@pFs`#qA$k%0KVRH735+ts?q@75_kb`f6BA;B9u z6E1}cOy4}eWDSR?Qw0c!Hn-t3LvYn}0mu7truNuNaAp63{GPSRCce(!yIXOrUWylv zUU28vJp9<~HwTB-60_Gg19dO2M*Vxi?B}Hflf;~pXC-FAAhXni36(ol?W>o*tpqsp5Oe9W z!oDqE;>ABpFZLEBZXm(Fww}VTH`T5D&JW513|eP6-8hrj^E2WX?OiYJ9PRPCb(z7ps`c0VZ$GS*w{(v0wXpn{D%>!x;|5%E$uVut(?;!uEDo2o z@{^`w7l=%;KGM(fRc3AWkKK3!;U^_3|1n-sEuLl{ri=T-<2Jpd^(|JB5fZ%3Ubu!$ z^QP0bi-`$`Gj8gYbJ_1@&Bb=xtSPQIy)T>k;^!fR_H2s&6yy?II3Lf*v#u`X7m{y3 zt_TFPR^(%rmxc105K8~=oL5NZu6_)f|%N|^=6Sj ze6UL_@_TXfJBLmW_-s9XywLZ=!y4>)JxoXzwOJ6zi3svO%EFyR`HEWNWPb9i_v06c z)GJD7?*ef-JyG@70c#(aHYU-R*1R2+2YEmJzJAoeRBV|6vkg09QDhZiTvT#$PPaAu zD3Nn@nBkS2DZjx{L5s{MY5#eQPeuz3`JX4a$MOVCIlwfIWfyk5Nf8hlTB+<2!4jhx z)qtjlSu~CQL9pHoJS@0mO$nIMf$m?6g11X7QM)>lHRto7Ff>Vvd zW`{72<*W74JW9rf_x9o(FGD@NQT9Sajb-ce18EybH}gtR!M%{AX5>?Smu`O0%c44_ z5#Ai=8}0#}fSzY)NB{2OrKzpsqY_s$o}(P{hu@NU`BvDGq9;0M@DdbSDcyT)H(8Qf zS_ z(^*esVMlYti!$@GXBg0v`btOm&u|KF@h#e+E1Jo{(0XERYAm*eNq9x*V&wa6B`WV$ zDYIe8dzM+Ov(r3%ExY+M4M00KEQs^!5W^$j}0^Tn-IyCEh(Bzp%)<>&&wfh zx~NF|z17BKV`YW8x;3KimbSHtzF&W>XIn>69Hg-Eg{g|YncqNDGrv%#EuLCM(_gv* zN!wqvRXrm+U2A#aX8woQ{tWwj>6KDlL>T-9I2X;fEYTUS7(j%|Qq0%|2AsuSnD{?m zV{L|~1)))uvjNy5PJx^RE{3n%k_4iSh${??hhG>HUH7#WlAG7_hkHqUWt<)^Mg=eL zW{35~i`Yw}<6q!%w_8u=F^eA99^c|KyXktX-Bm-d{{5t)SwSB8(M!WS1-(hqO!_{PR9wgn}%?%+>8~1sD z2UV)Iq9d}}ZXq5pF{4j&elppWKmZysQJMRyzIU@*i9ONexzUIl0-7 zx2~JNmGg5vMsro|3z)d5r<8UaW$dHmf<%$uZVAj)t2--j+D)69_bM3bJ#5uIAp@G zBdV*4i)F9gRW|y}dYK^WNv&K1RHX*|YaE==8F@6Q+}-R5wo)_b|{cPM&@J{TqoC3`e_ zn1>blwdv!{+`V+g;wFbKj_+mQl1Em&cl_Z;&HiL+INoD!*)WGNtq;nS)$@Bi<@}0p z$vuUXk_Au1aQi1yXBE56HF$Y}wD2kl_9>B?xKiUEy$;NGf#LpJ@ZMPg>%dWsf7cMd zgEa~@^;4Cgm0M6hIKVzhneyKy1WAev`x&^pqfLw1Vqs@}6b5Os<=nVNVa*4|W{qzR zX?x$~Sx%szot?>?we~aBFW^n^8MRsuq;}eF;LSU{pA~En%ZJFT?UoS6wlYm@)^`C8 zG+XfSphq8_M-*$w5evs^7PkpIe>J70dW~hPLzq`;SS7*H)lw?k&2)={xG}{K>eOrG zUP}^{?rRiBsWz(2fGD6isK`1=fbU@@iIU~1@8EPe=qOY2k4%}4%86BuUF~K(6PwTX z$M`sui0(bHF)3C5d@yhH)=RZ@P_@X_jB~y0v36xp4Oy%-^Z$IM&_XpeVk9-!&x}-+ zN`skd?!SjsYI?{G9nEo0=G$A;3)A68oewuiwNejE>n4j8#HG^OhcPzyYuW3OHeu7r zQ^8D11q`v|tz-r~rSHqByd9x$I#QJHH@V6qbkAJB;up8FYvR`TVzc_qFzn@1^#;&LI*YLvFAVG|@$!p&bYd6iPj8hv7#1Lm|k|5YgESq5h% zsGHb|ezD^xi_kL&fq^3qz&O^FQaeMJa=CCQq|G${$fS<-p5vZr=0I!6vW6ys+R%hz zQ_~S|P?e$^*6Art;)u7FrF5;-i)!sQdpvR6YoYY_-ovxT9^F`5_N6iuB8GLC6Oczn z9`eP>Vgm9k*zHQ_KdMTmoX$Z}oo$gYrnKXe|C_?n|NpkIy-Z^aTjw07z1T)0O6wjHNHOIADP30qO!QMv~z4+Y6 zD~C&nv#9OjydmZgAe(3-AT;GDq)qALV1B_$qrx@Fd8IRWtR4W-FVoPP{Q6&q9qSWx zB2nYRZHHyoegDjN!$v9oZBkQpn!W2rX?7j0&hgJH9?Lt(*j^AgXt%5SDvvDU>JX;5XevLh!Pu0-bG48H`W~-;_1phZT#Dp8*a!1+Z((A&$;kwlDSqZ_ zMf+vEGWKk?$|V1FLaAxG=_9DQ&v^7vj|41=nQ7$}4zAT;TU%KPZNnOZ-N*0nNHmI5 zY^Nn~E*R~VHIlIDkUgb;)DWL4hL!vZ8?OkaOpdgkol(^%((|*HW=A>vgC2N@vXt6c zSom}caav!kzudeIH-5;8tHLL2e7y!+8+%dgoH2N~xy^g=RdVez!;-hd(qMP0sTfonM^hilgUA9KrJoNtp0b0>8 literal 0 HcmV?d00001 From 757563c3aad8f7aadc85591fa60f669967c3281b Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Sun, 2 Aug 2026 13:06:03 +0200 Subject: [PATCH 16/43] docs: updated API docs --- api/textmode.export.js/index.md | 116 ++-- .../interfaces/ExportOverlayController.md | 265 ++++++++- .../methods/getDefaults.md | 39 -- .../methods/getPosition.md | 36 -- .../ExportOverlayController/methods/hide.md | 33 -- .../methods/isVisible.md | 33 -- .../methods/resetDefaults.md | 49 -- .../methods/resetPosition.md | 34 -- .../methods/setDefaults.md | 44 -- .../methods/setPosition.md | 40 -- .../ExportOverlayController/methods/show.md | 33 -- .../ExportOverlayController/methods/toggle.md | 33 -- .../interfaces/ExportOverlayPosition.md | 2 +- .../interfaces/ExportOverlayPositionInput.md | 2 +- .../interfaces/JSONCellTransform.md | 28 - .../interfaces/JSONExportMetadata.md | 28 - .../interfaces/JSONLayerGrid.md | 28 - .../interfaces/JSONObjectRowCell.md | 30 -- .../JSONObjectRowsCellCollection.md | 26 - .../interfaces/JSONRGBAColor.md | 28 - .../interfaces/LayerExportOptions.md | 2 +- .../interfaces/TextmodeAllDocumentJSON.md | 32 -- .../interfaces/TextmodeDocumentLayer.md | 33 -- .../interfaces/TextmodeExportAPI.md | 506 +++++++++++++++++- .../TextmodeExportAPI/methods/copyCanvas.md | 39 -- .../TextmodeExportAPI/methods/saveCanvas.md | 39 -- .../TextmodeExportAPI/methods/saveGIF.md | 39 -- .../TextmodeExportAPI/methods/saveJSON.md | 40 -- .../TextmodeExportAPI/methods/saveSVG.md | 39 -- .../TextmodeExportAPI/methods/saveStrings.md | 39 -- .../TextmodeExportAPI/methods/saveVideo.md | 48 -- .../TextmodeExportAPI/methods/toJSON.md | 42 -- .../TextmodeExportAPI/methods/toJSONString.md | 42 -- .../TextmodeExportAPI/methods/toSVG.md | 41 -- .../TextmodeExportAPI/methods/toString.md | 41 -- .../TextmodeSelectedDocumentJSON.md | 33 -- .../TextmodeSelectedDocumentLayer.md | 26 - .../type-aliases/ExportDefaults.md | 24 +- .../type-aliases/ExportDefaultsPatch.md | 4 +- .../type-aliases/GIFExportOptions.md | 52 +- .../type-aliases/GIFExportProgress.md | 26 +- .../type-aliases/GIFOverlayDefaults.md | 2 +- .../type-aliases/ImageExportOptions.md | 2 +- .../type-aliases/ImageOverlayDefaults.md | 2 +- .../type-aliases/JSONCellCollection.md | 22 - .../type-aliases/JSONColorValue.md | 22 - .../type-aliases/JSONDocumentFormat.md | 22 - .../type-aliases/JSONDocumentVersion.md | 22 - .../type-aliases/JSONExportColorMode.md | 2 +- .../type-aliases/JSONExportOptions.md | 8 +- .../type-aliases/JSONExportTarget.md | 2 +- .../type-aliases/JSONOverlayDefaults.md | 2 +- .../type-aliases/SVGExportOptions.md | 4 +- .../type-aliases/SVGOverlayDefaults.md | 2 +- .../type-aliases/TXTExportOptions.md | 4 +- .../type-aliases/TXTOverlayDefaults.md | 2 +- .../type-aliases/TextmodeDocumentJSON.md | 6 +- .../type-aliases/VideoBitrateMode.md | 2 +- .../type-aliases/VideoBitratePreset.md | 2 +- .../type-aliases/VideoExportErrorCode.md | 25 - .../type-aliases/VideoExportFormat.md | 2 +- .../type-aliases/VideoExportOptions.md | 117 ++-- .../type-aliases/VideoExportPhase.md | 2 +- .../type-aliases/VideoExportProgress.md | 44 +- .../type-aliases/VideoHardwareAcceleration.md | 2 +- .../type-aliases/VideoLatencyMode.md | 2 +- .../type-aliases/VideoOverlayDefaults.md | 2 +- .../type-aliases/VideoRecordingState.md | 2 +- api/textmode.export.js/typedoc-sidebar.json | 2 +- .../variables/ExportPlugin.md | 14 +- .../classes/TextmodeFigFont.md | 18 +- .../TextmodeFigFont/accessors/baseline.md | 2 +- .../TextmodeFigFont/accessors/characters.md | 2 +- .../accessors/defaultLayout.md | 2 +- .../accessors/defaultPrintDirection.md | 2 +- .../accessors/defaultVerticalLayout.md | 2 +- .../TextmodeFigFont/accessors/hardblank.md | 2 +- .../TextmodeFigFont/accessors/header.md | 2 +- .../TextmodeFigFont/accessors/height.md | 2 +- .../classes/TextmodeFigFont/accessors/name.md | 2 +- .../TextmodeFigFont/methods/addOnDispose.md | 2 +- .../TextmodeFigFont/methods/dispose.md | 2 +- .../TextmodeFigFont/methods/getCharacter.md | 2 +- .../TextmodeFigFont/methods/measureText.md | 2 +- .../TextmodeFigFont/methods/planText.md | 2 +- .../TextmodeFigFont/methods/renderText.md | 2 +- api/textmode.figlet.js/index.md | 73 ++- .../interfaces/FigCharacter.md | 2 +- .../interfaces/FigFontHeader.md | 12 +- .../interfaces/FigTextCellContext.md | 12 +- .../interfaces/FigTextOptions.md | 10 +- .../TextmodifierFigletExtensions.md | 12 +- .../methods/figFont.md | 2 +- .../methods/figText.md | 2 +- .../methods/figTextAlign.md | 2 +- .../methods/figTextBaseline.md | 2 +- .../methods/figTextBounds.md | 2 +- .../methods/figTextHeight.md | 2 +- .../methods/figTextWidth.md | 2 +- .../methods/loadFigFont.md | 2 +- .../methods/parseFigFont.md | 2 +- .../type-aliases/FigHorizontalLayout.md | 2 +- .../type-aliases/FigPrintDirection.md | 2 +- .../type-aliases/FigTextAlign.md | 2 +- .../type-aliases/FigTextBaseline.md | 2 +- .../type-aliases/FigTextColorResolver.md | 2 +- .../type-aliases/FigTextColorValue.md | 2 +- .../type-aliases/FigVerticalLayout.md | 2 +- .../type-aliases/FigWrapMode.md | 2 +- api/textmode.figlet.js/typedoc-sidebar.json | 2 +- .../variables/FigletPlugin.md | 2 +- .../functions/createFiltersPlugin.md | 44 -- api/textmode.filters.js/index.md | 58 +- .../interfaces/BloomOptions.md | 4 +- .../interfaces/BrightnessOptions.md | 2 +- .../interfaces/ChromaticAberrationOptions.md | 2 +- .../interfaces/ContrastOptions.md | 2 +- .../interfaces/CrtMattiasOptions.md | 2 +- .../interfaces/FilmGrainOptions.md | 2 +- .../interfaces/GlitchOptions.md | 2 +- .../interfaces/GridDistortionOptions.md | 8 +- .../interfaces/HueRotateOptions.md | 2 +- .../interfaces/PixelateOptions.md | 2 +- .../interfaces/PosterizeOptions.md | 2 +- .../interfaces/SaturationOptions.md | 2 +- .../interfaces/ScanlinesOptions.md | 4 +- .../interfaces/VignetteOptions.md | 4 +- api/textmode.filters.js/typedoc-sidebar.json | 2 +- .../variables/FiltersPlugin.md | 2 +- api/textmode.js/classes/TextmodeCamera.md | 2 +- .../classes/TextmodeCamera/accessors/eyeX.md | 2 +- .../classes/TextmodeCamera/accessors/eyeY.md | 2 +- .../classes/TextmodeCamera/accessors/eyeZ.md | 2 +- .../TextmodeCamera/accessors/targetX.md | 2 +- .../TextmodeCamera/accessors/targetY.md | 2 +- .../TextmodeCamera/accessors/targetZ.md | 2 +- .../classes/TextmodeCamera/accessors/upX.md | 2 +- .../classes/TextmodeCamera/accessors/upY.md | 2 +- .../classes/TextmodeCamera/accessors/upZ.md | 2 +- .../classes/TextmodeCamera/methods/copy.md | 2 +- .../classes/TextmodeCamera/methods/lookAt.md | 6 +- .../classes/TextmodeCamera/methods/move.md | 6 +- .../TextmodeCamera/methods/setPosition.md | 6 +- .../classes/TextmodeCamera/methods/setUp.md | 6 +- .../classes/TextmodeFramebuffer.md | 2 +- .../accessors/attachmentCount.md | 2 +- .../accessors/framebuffer.md | 2 +- .../TextmodeFramebuffer/accessors/height.md | 2 +- .../TextmodeFramebuffer/accessors/textures.md | 2 +- .../TextmodeFramebuffer/accessors/width.md | 2 +- .../TextmodeFramebuffer/methods/begin.md | 2 +- .../TextmodeFramebuffer/methods/dispose.md | 2 +- .../TextmodeFramebuffer/methods/end.md | 2 +- .../TextmodeFramebuffer/methods/readPixels.md | 2 +- .../TextmodeFramebuffer/methods/resize.md | 2 +- api/textmode.js/classes/TextmodeGlyphRamp.md | 6 +- api/textmode.js/classes/TextmodeGrid.md | 2 +- .../TextmodeGrid/accessors/cellHeight.md | 2 +- .../TextmodeGrid/accessors/cellWidth.md | 2 +- .../classes/TextmodeGrid/accessors/cols.md | 2 +- .../classes/TextmodeGrid/accessors/height.md | 2 +- .../classes/TextmodeGrid/accessors/offsetX.md | 2 +- .../classes/TextmodeGrid/accessors/offsetY.md | 2 +- .../classes/TextmodeGrid/accessors/rows.md | 2 +- .../classes/TextmodeGrid/accessors/width.md | 2 +- .../classes/TextmodeGrid/methods/reset.md | 2 +- .../TextmodeGrid/methods/responsive.md | 2 +- api/textmode.js/classes/TextmodeRandom.md | 2 +- api/textmode.js/classes/TextmodeShader.md | 7 +- api/textmode.js/classes/TextmodeVector.md | 6 +- .../classes/TextmodeVector/methods/add.md | 6 +- .../classes/TextmodeVector/methods/copy.md | 2 +- .../classes/TextmodeVector/methods/cross.md | 6 +- .../classes/TextmodeVector/methods/dist.md | 6 +- .../classes/TextmodeVector/methods/div.md | 6 +- .../classes/TextmodeVector/methods/dot.md | 6 +- .../classes/TextmodeVector/methods/heading.md | 2 +- .../classes/TextmodeVector/methods/limit.md | 2 +- .../classes/TextmodeVector/methods/mag.md | 2 +- .../classes/TextmodeVector/methods/magSq.md | 2 +- .../classes/TextmodeVector/methods/mult.md | 6 +- .../TextmodeVector/methods/normalize.md | 2 +- .../classes/TextmodeVector/methods/set.md | 6 +- .../classes/TextmodeVector/methods/setMag.md | 2 +- .../classes/TextmodeVector/methods/sub.md | 6 +- api/textmode.js/classes/Textmodifier.md | 464 ++++++++++------ .../classes/Textmodifier/accessors/canvas.md | 4 +- .../Textmodifier/accessors/conversions.md | 2 +- .../classes/Textmodifier/accessors/errors.md | 4 +- .../classes/Textmodifier/accessors/filters.md | 2 +- .../classes/Textmodifier/accessors/font.md | 4 +- .../Textmodifier/accessors/frameCount.md | 6 +- .../classes/Textmodifier/accessors/grid.md | 4 +- .../classes/Textmodifier/accessors/height.md | 4 +- .../Textmodifier/accessors/isDisposed.md | 4 +- .../accessors/isRenderingFrame.md | 4 +- .../classes/Textmodifier/accessors/layers.md | 2 +- .../classes/Textmodifier/accessors/loading.md | 2 +- .../classes/Textmodifier/accessors/millis.md | 10 +- .../classes/Textmodifier/accessors/overlay.md | 4 +- .../classes/Textmodifier/accessors/secs.md | 8 +- .../classes/Textmodifier/accessors/width.md | 4 +- .../classes/Textmodifier/methods/abs.md | 2 +- .../classes/Textmodifier/methods/acos.md | 2 +- .../Textmodifier/methods/ambientLight.md | 12 +- .../Textmodifier/methods/applyMatrix.md | 32 +- .../classes/Textmodifier/methods/arc.md | 8 +- .../classes/Textmodifier/methods/asin.md | 2 +- .../classes/Textmodifier/methods/atan.md | 2 +- .../classes/Textmodifier/methods/atan2.md | 2 +- .../Textmodifier/methods/background.md | 8 +- .../Textmodifier/methods/beginShape.md | 2 +- .../Textmodifier/methods/bezierCurve.md | 16 +- .../classes/Textmodifier/methods/box.md | 6 +- .../classes/Textmodifier/methods/camera.md | 18 +- .../classes/Textmodifier/methods/ceil.md | 2 +- .../classes/Textmodifier/methods/cellColor.md | 8 +- .../classes/Textmodifier/methods/char.md | 2 +- .../classes/Textmodifier/methods/charColor.md | 8 +- .../Textmodifier/methods/charRotation.md | 2 +- .../classes/Textmodifier/methods/clamp.md | 6 +- .../classes/Textmodifier/methods/clear.md | 2 +- .../classes/Textmodifier/methods/color.md | 8 +- .../classes/Textmodifier/methods/colorMode.md | 10 +- .../classes/Textmodifier/methods/cone.md | 2 +- .../classes/Textmodifier/methods/constrain.md | 6 +- .../classes/Textmodifier/methods/cos.md | 2 +- .../Textmodifier/methods/createCamera.md | 2 +- .../methods/createFilterShader.md | 46 -- .../Textmodifier/methods/createFramebuffer.md | 2 +- .../Textmodifier/methods/createGlyphRamp.md | 2 +- .../methods/createMaterialShader.md | 2 +- .../Textmodifier/methods/createShader.md | 2 +- .../Textmodifier/methods/createTexture.md | 2 +- .../Textmodifier/methods/createVector.md | 6 +- .../classes/Textmodifier/methods/cursor.md | 2 +- .../classes/Textmodifier/methods/cylinder.md | 2 +- .../classes/Textmodifier/methods/degrees.md | 2 +- .../classes/Textmodifier/methods/deltaTime.md | 4 +- .../classes/Textmodifier/methods/destroy.md | 4 +- .../classes/Textmodifier/methods/dist.md | 8 +- .../Textmodifier/methods/doubleClicked.md | 4 +- .../classes/Textmodifier/methods/doubleTap.md | 2 +- .../classes/Textmodifier/methods/draw.md | 4 +- .../classes/Textmodifier/methods/ease.md | 2 +- .../classes/Textmodifier/methods/ellipse.md | 2 +- .../classes/Textmodifier/methods/ellipsoid.md | 6 +- .../classes/Textmodifier/methods/endShape.md | 2 +- .../Textmodifier/methods/exitPointerLock.md | 2 +- .../classes/Textmodifier/methods/exp.md | 2 +- .../classes/Textmodifier/methods/fill.md | 8 +- .../classes/Textmodifier/methods/filter.md | 2 +- .../classes/Textmodifier/methods/finalDraw.md | 2 +- .../classes/Textmodifier/methods/flipX.md | 2 +- .../classes/Textmodifier/methods/flipY.md | 2 +- .../classes/Textmodifier/methods/floor.md | 2 +- .../classes/Textmodifier/methods/fontSize.md | 2 +- .../classes/Textmodifier/methods/fract.md | 2 +- .../classes/Textmodifier/methods/frameRate.md | 4 +- .../classes/Textmodifier/methods/gamepad.md | 4 +- .../methods/gamepadAxisChanged.md | 2 +- .../methods/gamepadButtonPressed.md | 2 +- .../methods/gamepadButtonReleased.md | 2 +- .../Textmodifier/methods/gamepadConnected.md | 2 +- .../methods/gamepadDisconnected.md | 2 +- .../classes/Textmodifier/methods/image.md | 6 +- .../classes/Textmodifier/methods/inputGrid.md | 4 +- .../classes/Textmodifier/methods/invert.md | 2 +- .../Textmodifier/methods/isKeyPressed.md | 2 +- .../classes/Textmodifier/methods/isLooping.md | 4 +- .../Textmodifier/methods/keyPressed.md | 2 +- .../Textmodifier/methods/keyReleased.md | 2 +- .../classes/Textmodifier/methods/keyTyped.md | 2 +- .../classes/Textmodifier/methods/lerp.md | 6 +- .../Textmodifier/methods/lightFalloff.md | 6 +- .../classes/Textmodifier/methods/line.md | 8 +- .../Textmodifier/methods/lineWeight.md | 2 +- .../classes/Textmodifier/methods/loadFont.md | 2 +- .../classes/Textmodifier/methods/loadImage.md | 2 +- .../Textmodifier/methods/loadTileset.md | 2 +- .../classes/Textmodifier/methods/loadVideo.md | 2 +- .../classes/Textmodifier/methods/log.md | 2 +- .../classes/Textmodifier/methods/longPress.md | 2 +- .../classes/Textmodifier/methods/lookAt.md | 12 +- .../classes/Textmodifier/methods/loop.md | 4 +- .../classes/Textmodifier/methods/map.md | 10 +- .../classes/Textmodifier/methods/max.md | 2 +- .../classes/Textmodifier/methods/min.md | 2 +- .../Textmodifier/methods/mouseClicked.md | 2 +- .../Textmodifier/methods/mouseDragged.md | 2 +- .../Textmodifier/methods/mouseMoved.md | 2 +- .../Textmodifier/methods/mousePressed.md | 2 +- .../Textmodifier/methods/mouseReleased.md | 2 +- .../Textmodifier/methods/mouseScrolled.md | 2 +- .../classes/Textmodifier/methods/noLights.md | 2 +- .../classes/Textmodifier/methods/noLoop.md | 4 +- .../classes/Textmodifier/methods/noTexture.md | 2 +- .../classes/Textmodifier/methods/noise.md | 6 +- .../Textmodifier/methods/noiseDetail.md | 2 +- .../classes/Textmodifier/methods/noiseSeed.md | 2 +- .../classes/Textmodifier/methods/norm.md | 6 +- .../classes/Textmodifier/methods/off.md | 2 +- .../classes/Textmodifier/methods/on.md | 2 +- .../classes/Textmodifier/methods/once.md | 2 +- .../classes/Textmodifier/methods/ortho.md | 2 +- .../Textmodifier/methods/perspective.md | 6 +- .../classes/Textmodifier/methods/pinch.md | 2 +- .../Textmodifier/methods/pixelDensity.md | 6 +- .../classes/Textmodifier/methods/point.md | 2 +- .../Textmodifier/methods/pointLight.md | 24 +- .../classes/Textmodifier/methods/pop.md | 2 +- .../classes/Textmodifier/methods/postDraw.md | 2 +- .../classes/Textmodifier/methods/pow.md | 2 +- .../classes/Textmodifier/methods/print.md | 8 +- .../Textmodifier/methods/printAlign.md | 2 +- .../classes/Textmodifier/methods/push.md | 2 +- .../classes/Textmodifier/methods/radians.md | 2 +- .../classes/Textmodifier/methods/random.md | 2 +- .../Textmodifier/methods/randomGaussian.md | 2 +- .../Textmodifier/methods/randomSeed.md | 2 +- .../Textmodifier/methods/randomStream.md | 2 +- .../classes/Textmodifier/methods/rect.md | 2 +- .../classes/Textmodifier/methods/redraw.md | 4 +- .../methods/requestPointerLock.md | 2 +- .../Textmodifier/methods/resetCamera.md | 2 +- .../Textmodifier/methods/resetMatrix.md | 2 +- .../Textmodifier/methods/resetShader.md | 2 +- .../Textmodifier/methods/resizeCanvas.md | 4 +- .../classes/Textmodifier/methods/rotate.md | 6 +- .../Textmodifier/methods/rotateGesture.md | 2 +- .../classes/Textmodifier/methods/rotateX.md | 2 +- .../classes/Textmodifier/methods/rotateY.md | 2 +- .../classes/Textmodifier/methods/rotateZ.md | 2 +- .../classes/Textmodifier/methods/round.md | 2 +- .../classes/Textmodifier/methods/scale.md | 6 +- .../classes/Textmodifier/methods/setCamera.md | 2 +- .../Textmodifier/methods/setUniform.md | 2 +- .../Textmodifier/methods/setUniforms.md | 2 +- .../classes/Textmodifier/methods/setup.md | 4 +- .../classes/Textmodifier/methods/shader.md | 2 +- .../classes/Textmodifier/methods/sin.md | 2 +- .../classes/Textmodifier/methods/sphere.md | 2 +- .../classes/Textmodifier/methods/sq.md | 2 +- .../classes/Textmodifier/methods/sqrt.md | 2 +- .../classes/Textmodifier/methods/stroke.md | 8 +- .../classes/Textmodifier/methods/swipe.md | 2 +- .../classes/Textmodifier/methods/tan.md | 2 +- .../classes/Textmodifier/methods/tap.md | 2 +- .../Textmodifier/methods/targetFrameRate.md | 4 +- .../classes/Textmodifier/methods/texture.md | 2 +- .../classes/Textmodifier/methods/torus.md | 2 +- .../Textmodifier/methods/touchCancelled.md | 2 +- .../Textmodifier/methods/touchEnded.md | 2 +- .../Textmodifier/methods/touchMoved.md | 2 +- .../Textmodifier/methods/touchStarted.md | 2 +- .../classes/Textmodifier/methods/translate.md | 6 +- .../Textmodifier/methods/translateX.md | 2 +- .../Textmodifier/methods/translateY.md | 2 +- .../Textmodifier/methods/translateZ.md | 2 +- .../classes/Textmodifier/methods/triangle.md | 12 +- .../Textmodifier/methods/useTileColors.md | 2 +- .../classes/Textmodifier/methods/vertex.md | 6 +- .../Textmodifier/methods/windowResized.md | 4 +- .../Textmodifier/properties/BLEND_ADDITIVE.md | 2 +- .../properties/BLEND_COLOR_BURN.md | 2 +- .../properties/BLEND_COLOR_DODGE.md | 2 +- .../Textmodifier/properties/BLEND_DARKEN.md | 2 +- .../properties/BLEND_DIFFERENCE.md | 2 +- .../properties/BLEND_EXCLUSION.md | 2 +- .../properties/BLEND_HARD_LIGHT.md | 2 +- .../Textmodifier/properties/BLEND_LIGHTEN.md | 2 +- .../Textmodifier/properties/BLEND_MULTIPLY.md | 2 +- .../Textmodifier/properties/BLEND_NORMAL.md | 2 +- .../Textmodifier/properties/BLEND_OVERLAY.md | 2 +- .../Textmodifier/properties/BLEND_SCREEN.md | 2 +- .../properties/BLEND_SOFT_LIGHT.md | 2 +- .../Textmodifier/properties/BLEND_SUBTRACT.md | 2 +- .../classes/Textmodifier/properties/LINES.md | 2 +- .../Textmodifier/properties/LINE_LOOP.md | 2 +- .../Textmodifier/properties/LINE_STRIP.md | 2 +- .../classes/Textmodifier/properties/POINTS.md | 2 +- .../classes/Textmodifier/properties/QUADS.md | 2 +- .../Textmodifier/properties/QUAD_STRIP.md | 2 +- .../Textmodifier/properties/TRIANGLES.md | 2 +- .../Textmodifier/properties/TRIANGLE_FAN.md | 2 +- .../Textmodifier/properties/TRIANGLE_STRIP.md | 2 +- .../Textmodifier/properties/displayHeight.md | 4 +- .../Textmodifier/properties/displayWidth.md | 4 +- .../Textmodifier/properties/gamepads.md | 2 +- .../Textmodifier/properties/lastKeyPressed.md | 2 +- .../properties/lastKeyReleased.md | 2 +- .../Textmodifier/properties/modifierState.md | 2 +- .../classes/Textmodifier/properties/mouse.md | 2 +- .../Textmodifier/properties/mouseIsPressed.md | 2 +- .../classes/Textmodifier/properties/movedX.md | 2 +- .../classes/Textmodifier/properties/movedY.md | 2 +- .../classes/Textmodifier/properties/pmouse.md | 2 +- .../Textmodifier/properties/pressedKeys.md | 2 +- .../Textmodifier/properties/touches.md | 2 +- .../Textmodifier/properties/windowHeight.md | 4 +- .../Textmodifier/properties/windowWidth.md | 4 +- api/textmode.js/classes/textmode.md | 2 +- .../classes/textmode/accessors/version.md | 2 +- .../classes/textmode/methods/create.md | 2 +- .../classes/textmode/methods/setErrorLevel.md | 2 +- .../enumerations/ShapeAssemblyMode.md | 2 +- api/textmode.js/index.md | 133 ++++- .../namespaces/color/classes/TextmodeColor.md | 2 +- .../TextmodeColor/accessors/normalized.md | 2 +- .../classes/TextmodeColor/accessors/rgb.md | 2 +- .../classes/TextmodeColor/accessors/rgba.md | 2 +- .../TextmodeColor/methods/withAlpha.md | 2 +- .../classes/TextmodeColor/properties/a.md | 2 +- .../classes/TextmodeColor/properties/b.md | 2 +- .../classes/TextmodeColor/properties/g.md | 2 +- .../classes/TextmodeColor/properties/r.md | 2 +- api/textmode.js/namespaces/color/index.md | 2 +- .../color/type-aliases/TextmodeColorMode.md | 2 +- .../type-aliases/TextmodeColorModeState.md | 2 +- .../color/type-aliases/TextmodeColorTuple.md | 4 +- .../classes/TextmodeConversionManager.md | 2 +- .../namespaces/conversion/index.md | 2 +- .../interfaces/TextmodeConversionContext.md | 2 +- .../TextmodeConversionPassContext.md | 2 +- .../interfaces/TextmodeConversionSource.md | 2 +- .../interfaces/TextmodeConversionStep.md | 2 +- .../interfaces/TextmodeConversionStrategy.md | 2 +- .../type-aliases/BuiltInConversionMode.md | 2 +- .../type-aliases/TextmodeColorInput.md | 4 +- .../type-aliases/TextmodeConversionMode.md | 2 +- .../TextmodeConversionStepOptions.md | 2 +- .../errors/classes/ErrorLayerController.md | 2 +- .../errors/classes/TextmodeError.md | 6 +- .../errors/enumerations/TextmodeErrorLevel.md | 2 +- api/textmode.js/namespaces/errors/index.md | 2 +- .../interfaces/ErrorScreenRendererContext.md | 2 +- .../interfaces/TextmodeErrorFormatOptions.md | 2 +- .../filters/classes/TextmodeFilterManager.md | 6 +- api/textmode.js/namespaces/filters/index.md | 2 +- .../filters/interfaces/BuiltInFilterParams.md | 2 +- .../filters/interfaces/FilterContext.md | 2 +- .../interfaces/TextmodeFilterStrategy.md | 2 +- .../filters/type-aliases/BuiltInFilterName.md | 2 +- .../filters/type-aliases/FilterName.md | 2 +- .../TextmodeFilterUniformDefinitions.md | 2 +- .../namespaces/fonts/classes/TextmodeFont.md | 2 +- .../TextmodeFont/accessors/characterMap.md | 2 +- .../TextmodeFont/accessors/characters.md | 2 +- .../classes/TextmodeFont/accessors/font.md | 2 +- .../TextmodeFont/accessors/fontSize.md | 2 +- .../TextmodeFont/accessors/framebuffer.md | 2 +- .../accessors/maxGlyphDimensions.md | 2 +- .../TextmodeFont/accessors/textureColumns.md | 2 +- .../TextmodeFont/accessors/textureRows.md | 2 +- .../classes/TextmodeFont/methods/dispose.md | 2 +- .../fonts/classes/TextmodeTileset.md | 2 +- .../accessors/cellDimensions.md | 2 +- .../TextmodeTileset/accessors/cellHeight.md | 2 +- .../TextmodeTileset/accessors/cellWidth.md | 2 +- .../TextmodeTileset/accessors/characterMap.md | 2 +- .../TextmodeTileset/accessors/characters.md | 2 +- .../TextmodeTileset/accessors/columns.md | 2 +- .../accessors/fontFramebuffer.md | 2 +- .../TextmodeTileset/accessors/fontSize.md | 2 +- .../TextmodeTileset/accessors/framebuffer.md | 2 +- .../accessors/maxGlyphDimensions.md | 2 +- .../accessors/nativeCellDimensions.md | 2 +- .../classes/TextmodeTileset/accessors/rows.md | 2 +- .../accessors/textureColumns.md | 2 +- .../TextmodeTileset/accessors/textureRows.md | 2 +- .../TextmodeTileset/methods/dispose.md | 2 +- api/textmode.js/namespaces/fonts/index.md | 2 +- .../namespaces/fonts/interfaces/GlyphData.md | 2 +- .../fonts/interfaces/GlyphDimensions.md | 2 +- .../fonts/interfaces/TextmodeGlyphAtlas.md | 2 +- .../interfaces/TextmodeTilesetOptions.md | 2 +- .../fonts/type-aliases/TextmodeGlyph.md | 2 +- api/textmode.js/namespaces/input/index.md | 2 +- .../input/namespaces/gamepad/index.md | 2 +- .../interfaces/GamepadAxisEventData.md | 2 +- .../interfaces/GamepadButtonEventData.md | 2 +- .../interfaces/GamepadConnectionEventData.md | 2 +- .../gamepad/interfaces/GamepadEventMap.md | 2 +- .../TextmodeGamepadButtonSnapshot.md | 2 +- .../interfaces/TextmodeGamepadSnapshot.md | 2 +- .../TextmodeGamepadStickSnapshot.md | 2 +- .../TextmodeStandardGamepadSnapshot.md | 2 +- .../type-aliases/GamepadAxisEventHandler.md | 2 +- .../type-aliases/GamepadButtonEventHandler.md | 2 +- .../GamepadConnectionEventHandler.md | 2 +- .../type-aliases/TextmodeStandardAxisName.md | 2 +- .../TextmodeStandardButtonName.md | 4 +- .../gamepad/variables/GAMEPAD_EVENT_NAMES.md | 2 +- .../input/namespaces/keyboard/index.md | 2 +- .../keyboard/interfaces/KeyboardEventData.md | 2 +- .../keyboard/interfaces/KeyboardEventMap.md | 2 +- .../type-aliases/KeyboardEventHandler.md | 2 +- .../variables/KEYBOARD_EVENT_NAMES.md | 2 +- .../input/namespaces/mouse/index.md | 2 +- .../mouse/interfaces/MouseEventData.md | 2 +- .../mouse/interfaces/MouseEventMap.md | 2 +- .../mouse/type-aliases/MouseEventHandler.md | 2 +- .../mouse/type-aliases/MousePosition.md | 2 +- .../mouse/variables/MOUSE_EVENT_NAMES.md | 2 +- .../input/namespaces/touch/index.md | 2 +- .../touch/interfaces/TouchEventData.md | 2 +- .../touch/interfaces/TouchEventMap.md | 2 +- .../interfaces/TouchLongPressEventData.md | 2 +- .../touch/interfaces/TouchPinchEventData.md | 2 +- .../touch/interfaces/TouchPosition.md | 2 +- .../touch/interfaces/TouchRotateEventData.md | 2 +- .../touch/interfaces/TouchSwipeEventData.md | 2 +- .../touch/interfaces/TouchTapEventData.md | 2 +- .../touch/type-aliases/TouchEventHandler.md | 2 +- .../type-aliases/TouchLongPressHandler.md | 2 +- .../touch/type-aliases/TouchPinchHandler.md | 2 +- .../touch/type-aliases/TouchRotateHandler.md | 2 +- .../touch/type-aliases/TouchSwipeHandler.md | 2 +- .../touch/type-aliases/TouchTapHandler.md | 2 +- .../touch/variables/GESTURE_EVENT_NAMES.md | 2 +- .../touch/variables/TOUCH_EVENT_NAMES.md | 2 +- .../input/type-aliases/InputEventMap.md | 2 +- .../input/type-aliases/InputEventName.md | 2 +- .../input/type-aliases/InputEventOwner.md | 2 +- .../input/variables/INPUT_EVENT_NAMES.md | 2 +- .../layering/classes/TextmodeLayer.md | 88 ++- .../accessors/asciiFramebuffer.md | 4 +- .../accessors/drawFramebuffer.md | 4 +- .../classes/TextmodeLayer/accessors/font.md | 4 +- .../classes/TextmodeLayer/accessors/grid.md | 2 +- .../classes/TextmodeLayer/accessors/height.md | 2 +- .../TextmodeLayer/accessors/texture.md | 2 +- .../classes/TextmodeLayer/accessors/width.md | 2 +- .../TextmodeLayer/methods/blendMode.md | 2 +- .../classes/TextmodeLayer/methods/camera.md | 18 +- .../TextmodeLayer/methods/createCamera.md | 2 +- .../methods/deletePluginState.md | 2 +- .../classes/TextmodeLayer/methods/draw.md | 2 +- .../classes/TextmodeLayer/methods/filter.md | 2 +- .../classes/TextmodeLayer/methods/fontSize.md | 2 +- .../TextmodeLayer/methods/getPluginState.md | 2 +- .../TextmodeLayer/methods/hasPluginState.md | 2 +- .../classes/TextmodeLayer/methods/hide.md | 2 +- .../classes/TextmodeLayer/methods/loadFont.md | 2 +- .../TextmodeLayer/methods/loadTileset.md | 2 +- .../classes/TextmodeLayer/methods/lookAt.md | 12 +- .../classes/TextmodeLayer/methods/offset.md | 4 +- .../classes/TextmodeLayer/methods/opacity.md | 2 +- .../classes/TextmodeLayer/methods/ortho.md | 2 +- .../TextmodeLayer/methods/perspective.md | 6 +- .../classes/TextmodeLayer/methods/postDraw.md | 2 +- .../TextmodeLayer/methods/resetCamera.md | 2 +- .../classes/TextmodeLayer/methods/rotateZ.md | 2 +- .../TextmodeLayer/methods/setCamera.md | 2 +- .../TextmodeLayer/methods/setPluginState.md | 2 +- .../classes/TextmodeLayer/methods/show.md | 2 +- .../TextmodeLayer/methods/useTileColors.md | 2 +- .../layering/classes/TextmodeLayerManager.md | 2 +- .../TextmodeLayerManager/accessors/all.md | 2 +- .../TextmodeLayerManager/accessors/base.md | 2 +- .../TextmodeLayerManager/accessors/filters.md | 2 +- .../accessors/resultFramebuffer.md | 2 +- .../TextmodeLayerManager/methods/add.md | 2 +- .../TextmodeLayerManager/methods/clear.md | 2 +- .../TextmodeLayerManager/methods/move.md | 2 +- .../TextmodeLayerManager/methods/remove.md | 2 +- .../TextmodeLayerManager/methods/swap.md | 2 +- .../layering/enumerations/LayerBlendMode.md | 2 +- api/textmode.js/namespaces/layering/index.md | 2 +- .../interfaces/TextmodeLayerOptions.md | 2 +- .../loading/classes/LoadingLayerController.md | 2 +- api/textmode.js/namespaces/loading/index.md | 2 +- .../interfaces/LoadingScreenOptions.md | 2 +- .../LoadingScreenRendererContext.md | 2 +- .../type-aliases/LoadingScreenState.md | 2 +- .../namespaces/media/classes/TextmodeImage.md | 43 +- .../classes/TextmodeImage/accessors/height.md | 2 +- .../TextmodeImage/accessors/originalHeight.md | 2 +- .../TextmodeImage/accessors/originalWidth.md | 2 +- .../TextmodeImage/accessors/texture.md | 2 +- .../classes/TextmodeImage/accessors/width.md | 2 +- .../TextmodeImage/methods/background.md | 8 +- .../TextmodeImage/methods/brightnessRange.md | 2 +- .../TextmodeImage/methods/cellColor.md | 8 +- .../TextmodeImage/methods/cellColorMode.md | 2 +- .../TextmodeImage/methods/charColor.md | 8 +- .../TextmodeImage/methods/charColorMode.md | 2 +- .../TextmodeImage/methods/charRotation.md | 2 +- .../TextmodeImage/methods/characters.md | 2 +- .../TextmodeImage/methods/clearConversions.md | 2 +- .../TextmodeImage/methods/conversionMode.md | 2 +- .../TextmodeImage/methods/conversions.md | 2 +- .../classes/TextmodeImage/methods/dispose.md | 2 +- .../classes/TextmodeImage/methods/flipX.md | 2 +- .../classes/TextmodeImage/methods/flipY.md | 2 +- .../classes/TextmodeImage/methods/invert.md | 2 +- .../media/classes/TextmodeSource.md | 51 +- .../TextmodeSource/accessors/height.md | 2 +- .../accessors/originalHeight.md | 2 +- .../TextmodeSource/accessors/originalWidth.md | 2 +- .../TextmodeSource/accessors/texture.md | 2 +- .../classes/TextmodeSource/accessors/width.md | 2 +- .../TextmodeSource/methods/background.md | 8 +- .../TextmodeSource/methods/brightnessRange.md | 2 +- .../TextmodeSource/methods/cellColor.md | 8 +- .../TextmodeSource/methods/cellColorMode.md | 2 +- .../TextmodeSource/methods/charColor.md | 8 +- .../TextmodeSource/methods/charColorMode.md | 2 +- .../TextmodeSource/methods/charRotation.md | 2 +- .../TextmodeSource/methods/characters.md | 2 +- .../methods/clearConversions.md | 2 +- .../TextmodeSource/methods/conversionMode.md | 2 +- .../TextmodeSource/methods/conversions.md | 2 +- .../classes/TextmodeSource/methods/dispose.md | 2 +- .../classes/TextmodeSource/methods/flipX.md | 2 +- .../classes/TextmodeSource/methods/flipY.md | 2 +- .../classes/TextmodeSource/methods/invert.md | 2 +- .../media/classes/TextmodeTexture.md | 50 +- .../TextmodeTexture/accessors/height.md | 2 +- .../accessors/originalHeight.md | 2 +- .../accessors/originalWidth.md | 2 +- .../TextmodeTexture/accessors/source.md | 2 +- .../TextmodeTexture/accessors/texture.md | 2 +- .../TextmodeTexture/accessors/width.md | 2 +- .../TextmodeTexture/methods/background.md | 8 +- .../methods/brightnessRange.md | 2 +- .../TextmodeTexture/methods/cellColor.md | 8 +- .../TextmodeTexture/methods/cellColorMode.md | 2 +- .../TextmodeTexture/methods/charColor.md | 8 +- .../TextmodeTexture/methods/charColorMode.md | 2 +- .../TextmodeTexture/methods/charRotation.md | 2 +- .../TextmodeTexture/methods/characters.md | 2 +- .../methods/clearConversions.md | 2 +- .../TextmodeTexture/methods/conversionMode.md | 2 +- .../TextmodeTexture/methods/conversions.md | 2 +- .../TextmodeTexture/methods/dispose.md | 2 +- .../classes/TextmodeTexture/methods/flipX.md | 2 +- .../classes/TextmodeTexture/methods/flipY.md | 2 +- .../classes/TextmodeTexture/methods/invert.md | 2 +- .../namespaces/media/classes/TextmodeVideo.md | 80 ++- .../TextmodeVideo/accessors/currentTime.md | 2 +- .../TextmodeVideo/accessors/duration.md | 2 +- .../classes/TextmodeVideo/accessors/height.md | 2 +- .../TextmodeVideo/accessors/isPlaying.md | 2 +- .../TextmodeVideo/accessors/originalHeight.md | 2 +- .../TextmodeVideo/accessors/originalWidth.md | 2 +- .../classes/TextmodeVideo/accessors/source.md | 2 +- .../TextmodeVideo/accessors/texture.md | 2 +- .../TextmodeVideo/accessors/videoElement.md | 2 +- .../classes/TextmodeVideo/accessors/width.md | 2 +- .../TextmodeVideo/methods/background.md | 8 +- .../TextmodeVideo/methods/brightnessRange.md | 2 +- .../TextmodeVideo/methods/cellColor.md | 8 +- .../TextmodeVideo/methods/cellColorMode.md | 2 +- .../TextmodeVideo/methods/charColor.md | 8 +- .../TextmodeVideo/methods/charColorMode.md | 2 +- .../TextmodeVideo/methods/charRotation.md | 2 +- .../TextmodeVideo/methods/characters.md | 2 +- .../TextmodeVideo/methods/clearConversions.md | 2 +- .../TextmodeVideo/methods/conversionMode.md | 2 +- .../TextmodeVideo/methods/conversions.md | 2 +- .../classes/TextmodeVideo/methods/dispose.md | 2 +- .../classes/TextmodeVideo/methods/flipX.md | 2 +- .../classes/TextmodeVideo/methods/flipY.md | 2 +- .../classes/TextmodeVideo/methods/invert.md | 2 +- .../classes/TextmodeVideo/methods/loop.md | 2 +- .../classes/TextmodeVideo/methods/pause.md | 2 +- .../classes/TextmodeVideo/methods/play.md | 2 +- .../classes/TextmodeVideo/methods/speed.md | 2 +- .../classes/TextmodeVideo/methods/stop.md | 2 +- .../classes/TextmodeVideo/methods/time.md | 2 +- .../classes/TextmodeVideo/methods/volume.md | 2 +- api/textmode.js/namespaces/media/index.md | 2 +- api/textmode.js/namespaces/plugins/index.md | 2 +- .../interfaces/TextmodeCanvasHandle.md | 2 +- .../plugins/interfaces/TextmodePlugin.md | 2 +- .../interfaces/TextmodePluginContext.md | 116 +++- .../methods/extendLayer.md | 2 +- .../methods/extendSource.md | 2 +- .../methods/registerLayerDisposedHook.md | 2 +- .../methods/registerLayerPostRenderHook.md | 2 +- .../methods/registerLayerPreRenderHook.md | 2 +- .../methods/registerPostDrawHook.md | 2 +- .../methods/registerPostSetupHook.md | 2 +- .../methods/registerPreDrawHook.md | 2 +- .../methods/registerPreSetupHook.md | 2 +- .../methods/removeLayerExtension.md | 2 +- .../methods/removeSourceExtension.md | 2 +- .../LayerExtensionImplementation.md | 2 +- .../type-aliases/LayerLifecycleHook.md | 2 +- .../plugins/type-aliases/LayerRenderHook.md | 2 +- .../type-aliases/SetupLifecycleHook.md | 2 +- .../SourceExtensionImplementation.md | 2 +- .../type-aliases/TextmodePluginHook.md | 2 +- .../TextmodeFramebufferOptions.md | 2 +- .../type-aliases/TextmodeOptions.md | 2 +- api/textmode.js/typedoc-sidebar.json | 2 +- api/textmode.synth.js/classes/SynthSource.md | 149 ++++-- .../classes/SynthSource/methods/add.md | 2 +- .../classes/SynthSource/methods/b.md | 2 +- .../classes/SynthSource/methods/barrel.md | 2 +- .../classes/SynthSource/methods/blend.md | 2 +- .../classes/SynthSource/methods/brightness.md | 2 +- .../classes/SynthSource/methods/burn.md | 2 +- .../classes/SynthSource/methods/cellColor.md | 2 +- .../classes/SynthSource/methods/char.md | 2 +- .../classes/SynthSource/methods/charColor.md | 2 +- .../classes/SynthSource/methods/charMap.md | 2 +- .../classes/SynthSource/methods/clamp.md | 2 +- .../classes/SynthSource/methods/clone.md | 2 +- .../classes/SynthSource/methods/color.md | 2 +- .../classes/SynthSource/methods/colorama.md | 2 +- .../classes/SynthSource/methods/contrast.md | 2 +- .../classes/SynthSource/methods/darken.md | 2 +- .../classes/SynthSource/methods/diff.md | 2 +- .../classes/SynthSource/methods/dodge.md | 2 +- .../classes/SynthSource/methods/fisheye.md | 2 +- .../classes/SynthSource/methods/g.md | 2 +- .../classes/SynthSource/methods/gamma.md | 2 +- .../classes/SynthSource/methods/gradient.md | 2 +- .../classes/SynthSource/methods/hardlight.md | 2 +- .../classes/SynthSource/methods/hue.md | 2 +- .../classes/SynthSource/methods/invert.md | 2 +- .../classes/SynthSource/methods/kaleid.md | 2 +- .../classes/SynthSource/methods/layer.md | 2 +- .../classes/SynthSource/methods/levels.md | 2 +- .../classes/SynthSource/methods/lighten.md | 2 +- .../classes/SynthSource/methods/luma.md | 2 +- .../classes/SynthSource/methods/mask.md | 2 +- .../classes/SynthSource/methods/mirror.md | 2 +- .../classes/SynthSource/methods/modulate.md | 2 +- .../SynthSource/methods/modulateHue.md | 2 +- .../SynthSource/methods/modulateKaleid.md | 2 +- .../SynthSource/methods/modulatePixelate.md | 2 +- .../SynthSource/methods/modulateRepeat.md | 2 +- .../SynthSource/methods/modulateRepeatX.md | 2 +- .../SynthSource/methods/modulateRepeatY.md | 2 +- .../SynthSource/methods/modulateRotate.md | 2 +- .../SynthSource/methods/modulateScale.md | 2 +- .../SynthSource/methods/modulateScrollX.md | 2 +- .../SynthSource/methods/modulateScrollY.md | 2 +- .../classes/SynthSource/methods/moire.md | 2 +- .../classes/SynthSource/methods/mult.md | 2 +- .../classes/SynthSource/methods/noise.md | 2 +- .../classes/SynthSource/methods/osc.md | 2 +- .../classes/SynthSource/methods/overlay.md | 2 +- .../classes/SynthSource/methods/paint.md | 2 +- .../classes/SynthSource/methods/pinch.md | 2 +- .../classes/SynthSource/methods/pixelate.md | 2 +- .../classes/SynthSource/methods/plasma.md | 2 +- .../classes/SynthSource/methods/polar.md | 2 +- .../classes/SynthSource/methods/posterize.md | 2 +- .../classes/SynthSource/methods/r.md | 2 +- .../classes/SynthSource/methods/repeat.md | 2 +- .../classes/SynthSource/methods/repeatX.md | 2 +- .../classes/SynthSource/methods/repeatY.md | 2 +- .../classes/SynthSource/methods/rotate.md | 2 +- .../classes/SynthSource/methods/saturate.md | 2 +- .../classes/SynthSource/methods/scale.md | 2 +- .../classes/SynthSource/methods/screen.md | 2 +- .../classes/SynthSource/methods/scroll.md | 2 +- .../classes/SynthSource/methods/scrollX.md | 2 +- .../classes/SynthSource/methods/scrollY.md | 2 +- .../classes/SynthSource/methods/seed.md | 2 +- .../classes/SynthSource/methods/shape.md | 2 +- .../classes/SynthSource/methods/shear.md | 2 +- .../classes/SynthSource/methods/shift.md | 2 +- .../classes/SynthSource/methods/softlight.md | 2 +- .../classes/SynthSource/methods/solid.md | 2 +- .../classes/SynthSource/methods/src.md | 2 +- .../classes/SynthSource/methods/sub.md | 2 +- .../classes/SynthSource/methods/swirl.md | 2 +- .../classes/SynthSource/methods/thresh.md | 2 +- .../classes/SynthSource/methods/twirl.md | 2 +- .../classes/SynthSource/methods/voronoi.md | 2 +- api/textmode.synth.js/functions/cellColor.md | 2 +- api/textmode.synth.js/functions/char.md | 2 +- api/textmode.synth.js/functions/charColor.md | 2 +- api/textmode.synth.js/functions/gradient.md | 2 +- api/textmode.synth.js/functions/moire.md | 2 +- api/textmode.synth.js/functions/noise.md | 2 +- api/textmode.synth.js/functions/osc.md | 2 +- api/textmode.synth.js/functions/paint.md | 2 +- api/textmode.synth.js/functions/plasma.md | 2 +- .../functions/setGlobalErrorCallback.md | 2 +- api/textmode.synth.js/functions/shape.md | 2 +- api/textmode.synth.js/functions/solid.md | 2 +- api/textmode.synth.js/functions/src.md | 2 +- api/textmode.synth.js/functions/voronoi.md | 2 +- api/textmode.synth.js/index.md | 95 ++-- .../interfaces/ModulatedArray.md | 8 +- .../interfaces/ModulatedArray/methods/ease.md | 7 +- .../interfaces/ModulatedArray/methods/fast.md | 7 +- .../interfaces/ModulatedArray/methods/fit.md | 7 +- .../ModulatedArray/methods/offset.md | 7 +- .../ModulatedArray/methods/smooth.md | 7 +- .../interfaces/SynthContext.md | 12 +- .../type-aliases/DynamicErrorCallback.md | 2 +- .../type-aliases/EasingFunction.md | 2 +- .../type-aliases/SynthParameterValue.md | 2 +- api/textmode.synth.js/typedoc-sidebar.json | 2 +- .../variables/EASING_FUNCTIONS.md | 18 +- .../variables/SynthPlugin.md | 2 +- 803 files changed, 3009 insertions(+), 3011 deletions(-) delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/getDefaults.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/getPosition.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/hide.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/isVisible.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/resetDefaults.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/resetPosition.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/setDefaults.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/setPosition.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/show.md delete mode 100644 api/textmode.export.js/interfaces/ExportOverlayController/methods/toggle.md delete mode 100644 api/textmode.export.js/interfaces/JSONCellTransform.md delete mode 100644 api/textmode.export.js/interfaces/JSONExportMetadata.md delete mode 100644 api/textmode.export.js/interfaces/JSONLayerGrid.md delete mode 100644 api/textmode.export.js/interfaces/JSONObjectRowCell.md delete mode 100644 api/textmode.export.js/interfaces/JSONObjectRowsCellCollection.md delete mode 100644 api/textmode.export.js/interfaces/JSONRGBAColor.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeDocumentLayer.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/copyCanvas.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveCanvas.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveGIF.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveJSON.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveSVG.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveStrings.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSON.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSONString.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toSVG.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toString.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md delete mode 100644 api/textmode.export.js/interfaces/TextmodeSelectedDocumentLayer.md delete mode 100644 api/textmode.export.js/type-aliases/JSONCellCollection.md delete mode 100644 api/textmode.export.js/type-aliases/JSONColorValue.md delete mode 100644 api/textmode.export.js/type-aliases/JSONDocumentFormat.md delete mode 100644 api/textmode.export.js/type-aliases/JSONDocumentVersion.md delete mode 100644 api/textmode.export.js/type-aliases/VideoExportErrorCode.md delete mode 100644 api/textmode.filters.js/functions/createFiltersPlugin.md delete mode 100644 api/textmode.js/classes/Textmodifier/methods/createFilterShader.md diff --git a/api/textmode.export.js/index.md b/api/textmode.export.js/index.md index ea041131..7821d80f 100644 --- a/api/textmode.export.js/index.md +++ b/api/textmode.export.js/index.md @@ -7,91 +7,83 @@ category: API Reference api: true kind: Project ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- # textmode.export.js -Export plugin for textmode.js - save artworks as images, videos, SVG, JSON, and text. +Export finished textmode.js artworks without leaving the sketch. -This plugin adds comprehensive export capabilities to textmode.js instances, -allowing you to save your generative artworks in multiple formats with a -convenient overlay UI for quick access to all export options. +## Choose an output -## Available export formats +Use **canvas capture** for the exact image on screen: PNG, JPEG, WebP, GIF, +or video preserve compositing, filters, shaders, and post-processing. Use +**layer data export** when the artwork should stay editable or machine +readable: TXT, SVG, and JSON read from the selected layer, while JSON can +also describe the full layer stack. -### Image formats -- [PNG/JPEG/WebP](type-aliases/ImageExportOptions.md) - Save canvas as raster image +Start with [ExportPlugin](variables/ExportPlugin.md), then call the helpers added to your sketch +or use the built-in export overlay. For recipes and format trade-offs, read +the [Exporting guide](/docs/exporting). -### Vector formats -- [SVG](type-aliases/SVGExportOptions.md) - Save as scalable vector graphics +## Animation export -### Text formats -- [TXT](type-aliases/TXTExportOptions.md) - Save text content as plain text -- [JSON](type-aliases/JSONExportOptions.md) - Save document data as structured JSON - -### Animation formats -- [GIF](type-aliases/GIFExportOptions.md) - Save as animated GIF -- [Video](type-aliases/VideoExportOptions.md) - Save as WebM or MP4 video +| Type Alias | Description | +| ------ | ------ | +| [GIFExportOptions](type-aliases/GIFExportOptions.md) | Options for exporting the textmode content to GIF format. | +| [GIFExportProgress](type-aliases/GIFExportProgress.md) | Progress information emitted during the GIF export process. | +| [VideoBitrateMode](type-aliases/VideoBitrateMode.md) | Bitrate allocation strategy for the native encoder. | +| [VideoBitratePreset](type-aliases/VideoBitratePreset.md) | Subjective bitrate preset used when an exact bits-per-second value is not supplied. | +| [VideoExportFormat](type-aliases/VideoExportFormat.md) | Video container format written by `saveVideo`. | +| [VideoExportOptions](type-aliases/VideoExportOptions.md) | Options for exporting the textmode content to video format. | +| [VideoExportPhase](type-aliases/VideoExportPhase.md) | More granular phase information for progress UIs that need to distinguish setup, rendering, and finalization. | +| [VideoExportProgress](type-aliases/VideoExportProgress.md) | Progress information emitted during the video export process. | +| [VideoHardwareAcceleration](type-aliases/VideoHardwareAcceleration.md) | WebCodecs hardware acceleration preference. | +| [VideoLatencyMode](type-aliases/VideoLatencyMode.md) | Encoder scheduling mode. | +| [VideoRecordingState](type-aliases/VideoRecordingState.md) | Lifecycle state reported while a video export is being prepared, recorded, encoded, or completed. | -## Interfaces +## Canvas capture -| Interface | Description | +| Type Alias | Description | | ------ | ------ | -| [LayerExportOptions](interfaces/LayerExportOptions.md) | Shared option for exporters that read layer framebuffer data. | -| [JSONRGBAColor](interfaces/JSONRGBAColor.md) | RGBA color representation used in JSON exports. | -| [JSONCellTransform](interfaces/JSONCellTransform.md) | Cell transform data for JSON exports. | -| [JSONObjectRowCell](interfaces/JSONObjectRowCell.md) | Rich per-cell representation for readable JSON exports. | -| [JSONObjectRowsCellCollection](interfaces/JSONObjectRowsCellCollection.md) | Row-based cell encoding. | -| [JSONLayerGrid](interfaces/JSONLayerGrid.md) | Grid dimensions exported for a layer. | -| [JSONExportMetadata](interfaces/JSONExportMetadata.md) | Optional export metadata. | -| [TextmodeSelectedDocumentLayer](interfaces/TextmodeSelectedDocumentLayer.md) | Selected-layer entry in a JSON document export. | -| [TextmodeSelectedDocumentJSON](interfaces/TextmodeSelectedDocumentJSON.md) | Selected-layer document exported by the JSON exporter. | -| [TextmodeDocumentLayer](interfaces/TextmodeDocumentLayer.md) | Single layer entry in an all-layers JSON export. | -| [TextmodeAllDocumentJSON](interfaces/TextmodeAllDocumentJSON.md) | Layer stack document exported by the JSON exporter. | -| [ExportOverlayPosition](interfaces/ExportOverlayPosition.md) | Current canvas-relative placement state for the export overlay UI. | -| [ExportOverlayPositionInput](interfaces/ExportOverlayPositionInput.md) | Canvas-relative placement coordinates for the export overlay UI. | -| [ExportOverlayController](interfaces/ExportOverlayController.md) | Controller for managing the export overlay UI visibility at runtime. | -| [TextmodeExportAPI](interfaces/TextmodeExportAPI.md) | Runtime export helpers that `ExportPlugin` attaches to the `Textmodifier` instance. | +| [ImageExportOptions](type-aliases/ImageExportOptions.md) | Options for exporting the textmode content to image format. | -## Type Aliases +## JSON document data | Type Alias | Description | | ------ | ------ | -| [GIFExportProgress](type-aliases/GIFExportProgress.md) | Progress information emitted during the GIF export process. | -| [GIFExportOptions](type-aliases/GIFExportOptions.md) | Options for exporting the textmode content to GIF format. | -| [ImageExportOptions](type-aliases/ImageExportOptions.md) | Options for exporting the textmode content to image format. | -| [JSONExportTarget](type-aliases/JSONExportTarget.md) | Target scope for JSON export. | -| [JSONDocumentFormat](type-aliases/JSONDocumentFormat.md) | Canonical JSON document format identifier. | -| [JSONDocumentVersion](type-aliases/JSONDocumentVersion.md) | Canonical JSON document format version. | | [JSONExportColorMode](type-aliases/JSONExportColorMode.md) | Supported JSON color output modes. | -| [JSONColorValue](type-aliases/JSONColorValue.md) | Color value used in the exported JSON document. | -| [JSONCellCollection](type-aliases/JSONCellCollection.md) | Supported JSON cell collection variants. | -| [TextmodeDocumentJSON](type-aliases/TextmodeDocumentJSON.md) | JSON document exported by the JSON exporter. | | [JSONExportOptions](type-aliases/JSONExportOptions.md) | Options for exporting the textmode content to JSON format. | +| [JSONExportTarget](type-aliases/JSONExportTarget.md) | Target scope for JSON export. | +| [TextmodeDocumentJSON](type-aliases/TextmodeDocumentJSON.md) | JSON document exported by the JSON exporter. | + +## Layer data export + +| Name | Description | +| ------ | ------ | +| [LayerExportOptions](interfaces/LayerExportOptions.md) | Shared option for exporters that read layer framebuffer data. | | [SVGExportOptions](type-aliases/SVGExportOptions.md) | Options for exporting the textmode content to SVG format. | | [TXTExportOptions](type-aliases/TXTExportOptions.md) | Options for exporting the textmode content to TXT format. | -| [VideoRecordingState](type-aliases/VideoRecordingState.md) | Lifecycle state reported while a video export is being prepared, recorded, encoded, or completed. | -| [VideoExportPhase](type-aliases/VideoExportPhase.md) | More granular phase information for progress UIs that need to distinguish setup, rendering, and finalization. | -| [VideoBitratePreset](type-aliases/VideoBitratePreset.md) | Subjective bitrate preset used when an exact bits-per-second value is not supplied. | -| [VideoExportFormat](type-aliases/VideoExportFormat.md) | Video container format written by `saveVideo`. | -| [VideoBitrateMode](type-aliases/VideoBitrateMode.md) | Bitrate allocation strategy for the native encoder. | -| [VideoLatencyMode](type-aliases/VideoLatencyMode.md) | Encoder scheduling mode. | -| [VideoHardwareAcceleration](type-aliases/VideoHardwareAcceleration.md) | WebCodecs hardware acceleration preference. | -| [VideoExportErrorCode](type-aliases/VideoExportErrorCode.md) | - | -| [VideoExportProgress](type-aliases/VideoExportProgress.md) | Progress information emitted during the video export process. | -| [VideoExportOptions](type-aliases/VideoExportOptions.md) | Options for exporting the textmode content to video format. | -| [TXTOverlayDefaults](type-aliases/TXTOverlayDefaults.md) | Default TXT export fields controlled by the export overlay. | -| [JSONOverlayDefaults](type-aliases/JSONOverlayDefaults.md) | Default JSON export fields controlled by the export overlay. | + +## Overlay + +| Name | Description | +| ------ | ------ | +| [ExportOverlayController](interfaces/ExportOverlayController.md) | Controller for managing the export overlay UI visibility at runtime. | +| [ExportOverlayPosition](interfaces/ExportOverlayPosition.md) | Current canvas-relative placement state for the export overlay UI. | +| [ExportOverlayPositionInput](interfaces/ExportOverlayPositionInput.md) | Canvas-relative placement coordinates for the export overlay UI. | +| [ExportDefaults](type-aliases/ExportDefaults.md) | Per-format default options used to seed the overlay UI inputs at mount time and after a [ExportOverlayController.resetDefaults](interfaces/ExportOverlayController.md#resetdefaults) call. | +| [ExportDefaultsPatch](type-aliases/ExportDefaultsPatch.md) | Partial patch accepted by [ExportOverlayController.setDefaults](interfaces/ExportOverlayController.md#setdefaults). | +| [GIFOverlayDefaults](type-aliases/GIFOverlayDefaults.md) | Default GIF export fields controlled by the export overlay. | | [ImageOverlayDefaults](type-aliases/ImageOverlayDefaults.md) | Default image export fields controlled by the export overlay. | +| [JSONOverlayDefaults](type-aliases/JSONOverlayDefaults.md) | Default JSON export fields controlled by the export overlay. | | [SVGOverlayDefaults](type-aliases/SVGOverlayDefaults.md) | Default SVG export fields controlled by the export overlay. | -| [GIFOverlayDefaults](type-aliases/GIFOverlayDefaults.md) | Default GIF export fields controlled by the export overlay. | +| [TXTOverlayDefaults](type-aliases/TXTOverlayDefaults.md) | Default TXT export fields controlled by the export overlay. | | [VideoOverlayDefaults](type-aliases/VideoOverlayDefaults.md) | Default video export fields controlled by the export overlay. | -| [ExportDefaults](type-aliases/ExportDefaults.md) | Per-format default options used to seed the overlay UI inputs at mount time and after a [ExportOverlayController.resetDefaults](interfaces/ExportOverlayController/methods/resetDefaults.md) call. | -| [ExportDefaultsPatch](type-aliases/ExportDefaultsPatch.md) | Partial patch accepted by [ExportOverlayController.setDefaults](interfaces/ExportOverlayController/methods/setDefaults.md). | -## Variables +## Workflow -| Variable | Description | +| Name | Description | | ------ | ------ | -| [ExportPlugin](variables/ExportPlugin.md) | Export plugin for textmode.js. | +| [TextmodeExportAPI](interfaces/TextmodeExportAPI.md) | Runtime export helpers that `ExportPlugin` attaches to the `Textmodifier` instance. | +| [ExportPlugin](variables/ExportPlugin.md) | Default export plugin instance for the standard textmode.js workflow. | diff --git a/api/textmode.export.js/interfaces/ExportOverlayController.md b/api/textmode.export.js/interfaces/ExportOverlayController.md index 31543071..25d75de6 100644 --- a/api/textmode.export.js/interfaces/ExportOverlayController.md +++ b/api/textmode.export.js/interfaces/ExportOverlayController.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -20,15 +20,254 @@ Controller for managing the export overlay UI visibility at runtime. ## Methods -| Method | Description | -| ------ | ------ | -| [show](ExportOverlayController/methods/show.md) | Shows the export overlay UI. | -| [hide](ExportOverlayController/methods/hide.md) | Hides the export overlay UI. | -| [toggle](ExportOverlayController/methods/toggle.md) | Toggles the export overlay UI visibility. | -| [isVisible](ExportOverlayController/methods/isVisible.md) | Checks if the export overlay is currently visible. | -| [resetPosition](ExportOverlayController/methods/resetPosition.md) | Restores the export overlay to its default canvas-relative placement and clears any remembered placement. | -| [getPosition](ExportOverlayController/methods/getPosition.md) | Reads the current export overlay placement. | -| [setPosition](ExportOverlayController/methods/setPosition.md) | Moves the export overlay to a custom canvas-relative placement and remembers that placement for future sessions on the same origin. | -| [setDefaults](ExportOverlayController/methods/setDefaults.md) | Override the curated overlay defaults at runtime. | -| [getDefaults](ExportOverlayController/methods/getDefaults.md) | Read the current effective defaults for every format. | -| [resetDefaults](ExportOverlayController/methods/resetDefaults.md) | Restore one or all formats to the library's curated defaults. | +### getDefaults() + +```ts +getDefaults(): Readonly; +``` + +Read the current effective defaults for every format. + +The returned object reflects the library's curated defaults merged +with any runtime overrides applied via [setDefaults](#setdefaults). + +#### Returns + +`Readonly`\<[`ExportDefaults`](../type-aliases/ExportDefaults.md)\> + +The current per-format defaults. + +#### Example + +```ts +const defaults = t.exportOverlay.getDefaults(); +console.log(defaults.image.scale); // 1 (or whatever was set) +``` + + +*** + +### getPosition() + +```ts +getPosition(): Readonly; +``` + +Reads the current export overlay placement. + +#### Returns + +`Readonly`\<[`ExportOverlayPosition`](ExportOverlayPosition.md)\> + +The current canvas-relative overlay placement state. + +#### Example + +```ts +const position = t.exportOverlay.getPosition(); +console.log(position.mode, position.offsetX, position.offsetY); +``` + + +*** + +### hide() + +```ts +hide(): void; +``` + +Hides the export overlay UI. + +#### Returns + +`void` + +#### Example + +```ts +t.exportOverlay.hide(); +``` + + +*** + +### isVisible() + +```ts +isVisible(): boolean; +``` + +Checks if the export overlay is currently visible. + +#### Returns + +`boolean` + +#### Example + +```ts +const visible = t.exportOverlay.isVisible(); +``` + + +*** + +### resetDefaults() + +```ts +resetDefaults(format?): void; +``` + +Restore one or all formats to the library's curated defaults. + +If a format is specified, only that format is reset; otherwise all +formats are restored. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `format?` | keyof ExportDefaults | Optional format to reset. Omit to reset all. | + +#### Returns + +`void` + +#### Example + +```ts +// Reset image defaults +t.exportOverlay.resetDefaults('image'); + +// Reset the overlay's selected default export format +t.exportOverlay.resetDefaults('format'); + +// Reset all formats +t.exportOverlay.resetDefaults(); +``` + + +*** + +### resetPosition() + +```ts +resetPosition(): void; +``` + +Restores the export overlay to its default canvas-relative placement and +clears any remembered placement. + +#### Returns + +`void` + +#### Example + +```ts +t.exportOverlay.resetPosition(); +``` + + +*** + +### setDefaults() + +```ts +setDefaults(patch): void; +``` + +Override the curated overlay defaults at runtime. + +Merges the supplied patch into the internal defaults store. Per-format +option patches are pushed into mounted blades; top-level `format` updates +the overlay's selected export format immediately. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `patch` | [`ExportDefaultsPatch`](../type-aliases/ExportDefaultsPatch.md) | Partial defaults to merge per format. | + +#### Returns + +`void` + +#### Example + +```ts +// Select image export by default, set image scale to 2×, and GIF to 30 fps +t.exportOverlay.setDefaults({ format: 'image', image: { scale: 2 }, gif: { frameRate: 30 } }); +``` + + +*** + +### setPosition() + +```ts +setPosition(position): void; +``` + +Moves the export overlay to a custom canvas-relative placement and +remembers that placement for future sessions on the same origin. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `position` | [`ExportOverlayPositionInput`](ExportOverlayPositionInput.md) | Canvas-relative overlay offsets in CSS pixels. | + +#### Returns + +`void` + +#### Example + +```ts +t.exportOverlay.setPosition({ offsetX: 24, offsetY: 24 }); +``` + + +*** + +### show() + +```ts +show(): void; +``` + +Shows the export overlay UI. + +#### Returns + +`void` + +#### Example + +```ts +t.exportOverlay.show(); +``` + + +*** + +### toggle() + +```ts +toggle(): void; +``` + +Toggles the export overlay UI visibility. + +#### Returns + +`void` + +#### Example + +```ts +t.exportOverlay.toggle(); +``` + diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/getDefaults.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/getDefaults.md deleted file mode 100644 index f5ffa8e5..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/getDefaults.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: getDefaults -description: Read the current effective defaults for every format. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / getDefaults - -# Method: getDefaults() - -```ts -getDefaults(): Readonly; -``` - -Read the current effective defaults for every format. - -The returned object reflects the library's curated defaults merged -with any runtime overrides applied via [setDefaults](setDefaults.md). - -## Returns - -`Readonly`\<[`ExportDefaults`](../../../type-aliases/ExportDefaults.md)\> - -The current per-format defaults. - -## Example - -```ts -const defaults = t.exportOverlay.getDefaults(); -console.log(defaults.image.scale); // 1 (or whatever was set) -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/getPosition.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/getPosition.md deleted file mode 100644 index 4821b96e..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/getPosition.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -layout: doc -editLink: true -title: getPosition -description: Reads the current export overlay placement. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / getPosition - -# Method: getPosition() - -```ts -getPosition(): Readonly; -``` - -Reads the current export overlay placement. - -## Returns - -`Readonly`\<[`ExportOverlayPosition`](../../ExportOverlayPosition.md)\> - -The current canvas-relative overlay placement state. - -## Example - -```ts -const position = t.exportOverlay.getPosition(); -console.log(position.mode, position.offsetX, position.offsetY); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/hide.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/hide.md deleted file mode 100644 index 45a72973..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/hide.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: hide -description: Hides the export overlay UI. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / hide - -# Method: hide() - -```ts -hide(): void; -``` - -Hides the export overlay UI. - -## Returns - -`void` - -## Example - -```ts -t.exportOverlay.hide(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/isVisible.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/isVisible.md deleted file mode 100644 index 409f2194..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/isVisible.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: isVisible -description: Checks if the export overlay is currently visible. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / isVisible - -# Method: isVisible() - -```ts -isVisible(): boolean; -``` - -Checks if the export overlay is currently visible. - -## Returns - -`boolean` - -## Example - -```ts -const visible = t.exportOverlay.isVisible(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetDefaults.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetDefaults.md deleted file mode 100644 index 97b2da73..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetDefaults.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -layout: doc -editLink: true -title: resetDefaults -description: Restore one or all formats to the library's curated defaults. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / resetDefaults - -# Method: resetDefaults() - -```ts -resetDefaults(format?): void; -``` - -Restore one or all formats to the library's curated defaults. - -If a format is specified, only that format is reset; otherwise all -formats are restored. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `format?` | keyof ExportDefaults | Optional format to reset. Omit to reset all. | - -## Returns - -`void` - -## Example - -```ts -// Reset image defaults -t.exportOverlay.resetDefaults('image'); - -// Reset the overlay's selected default export format -t.exportOverlay.resetDefaults('format'); - -// Reset all formats -t.exportOverlay.resetDefaults(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetPosition.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetPosition.md deleted file mode 100644 index cadd973d..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetPosition.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -layout: doc -editLink: true -title: resetPosition -description: Restores the export overlay to its default canvas-relative placement and clears any remembered placement. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / resetPosition - -# Method: resetPosition() - -```ts -resetPosition(): void; -``` - -Restores the export overlay to its default canvas-relative placement and -clears any remembered placement. - -## Returns - -`void` - -## Example - -```ts -t.exportOverlay.resetPosition(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/setDefaults.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/setDefaults.md deleted file mode 100644 index 533d4290..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/setDefaults.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -layout: doc -editLink: true -title: setDefaults -description: Override the curated overlay defaults at runtime. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / setDefaults - -# Method: setDefaults() - -```ts -setDefaults(patch): void; -``` - -Override the curated overlay defaults at runtime. - -Merges the supplied patch into the internal defaults store. Per-format -option patches are pushed into mounted blades; top-level `format` updates -the overlay's selected export format immediately. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `patch` | [`ExportDefaultsPatch`](../../../type-aliases/ExportDefaultsPatch.md) | Partial defaults to merge per format. | - -## Returns - -`void` - -## Example - -```ts -// Select image export by default, set image scale to 2×, and GIF to 30 fps -t.exportOverlay.setDefaults({ format: 'image', image: { scale: 2 }, gif: { frameRate: 30 } }); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/setPosition.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/setPosition.md deleted file mode 100644 index d4c3c7eb..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/setPosition.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -layout: doc -editLink: true -title: setPosition -description: Moves the export overlay to a custom canvas-relative placement and remembers that placement for future sessions on the same origin. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / setPosition - -# Method: setPosition() - -```ts -setPosition(position): void; -``` - -Moves the export overlay to a custom canvas-relative placement and -remembers that placement for future sessions on the same origin. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `position` | [`ExportOverlayPositionInput`](../../ExportOverlayPositionInput.md) | Canvas-relative overlay offsets in CSS pixels. | - -## Returns - -`void` - -## Example - -```ts -t.exportOverlay.setPosition({ offsetX: 24, offsetY: 24 }); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/show.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/show.md deleted file mode 100644 index a55b1bd2..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/show.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: show -description: Shows the export overlay UI. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / show - -# Method: show() - -```ts -show(): void; -``` - -Shows the export overlay UI. - -## Returns - -`void` - -## Example - -```ts -t.exportOverlay.show(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayController/methods/toggle.md b/api/textmode.export.js/interfaces/ExportOverlayController/methods/toggle.md deleted file mode 100644 index 54064af8..00000000 --- a/api/textmode.export.js/interfaces/ExportOverlayController/methods/toggle.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: toggle -description: Toggles the export overlay UI visibility. -category: Methods -api: true -owner: ExportOverlayController -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [ExportOverlayController](../../ExportOverlayController.md) / toggle - -# Method: toggle() - -```ts -toggle(): void; -``` - -Toggles the export overlay UI visibility. - -## Returns - -`void` - -## Example - -```ts -t.exportOverlay.toggle(); -``` - diff --git a/api/textmode.export.js/interfaces/ExportOverlayPosition.md b/api/textmode.export.js/interfaces/ExportOverlayPosition.md index 65f8c319..76999eb8 100644 --- a/api/textmode.export.js/interfaces/ExportOverlayPosition.md +++ b/api/textmode.export.js/interfaces/ExportOverlayPosition.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md b/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md index ed3e1164..f46a9d30 100644 --- a/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md +++ b/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.export.js/interfaces/JSONCellTransform.md b/api/textmode.export.js/interfaces/JSONCellTransform.md deleted file mode 100644 index 5d77f5f5..00000000 --- a/api/textmode.export.js/interfaces/JSONCellTransform.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONCellTransform -description: Cell transform data for JSON exports. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONCellTransform - -# Interface: JSONCellTransform - -Cell transform data for JSON exports. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `invert` | `boolean` | -| `flipX` | `boolean` | -| `flipY` | `boolean` | -| `rotation` | `number` | diff --git a/api/textmode.export.js/interfaces/JSONExportMetadata.md b/api/textmode.export.js/interfaces/JSONExportMetadata.md deleted file mode 100644 index c8a58f7e..00000000 --- a/api/textmode.export.js/interfaces/JSONExportMetadata.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONExportMetadata -description: Optional export metadata. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONExportMetadata - -# Interface: JSONExportMetadata - -Optional export metadata. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `createdAt` | `string` | -| `generator` | `object` | -| `generator.name` | `"textmode.export.js"` | -| `generator.version` | `string` | diff --git a/api/textmode.export.js/interfaces/JSONLayerGrid.md b/api/textmode.export.js/interfaces/JSONLayerGrid.md deleted file mode 100644 index 18e85101..00000000 --- a/api/textmode.export.js/interfaces/JSONLayerGrid.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONLayerGrid -description: Grid dimensions exported for a layer. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONLayerGrid - -# Interface: JSONLayerGrid - -Grid dimensions exported for a layer. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `cols` | `number` | -| `rows` | `number` | -| `cellWidth` | `number` | -| `cellHeight` | `number` | diff --git a/api/textmode.export.js/interfaces/JSONObjectRowCell.md b/api/textmode.export.js/interfaces/JSONObjectRowCell.md deleted file mode 100644 index 66bed261..00000000 --- a/api/textmode.export.js/interfaces/JSONObjectRowCell.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONObjectRowCell -description: Rich per-cell representation for readable JSON exports. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONObjectRowCell - -# Interface: JSONObjectRowCell - -Rich per-cell representation for readable JSON exports. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `x` | `number` | -| `y` | `number` | -| `character` | `string` | -| `foreground` | [`JSONColorValue`](../type-aliases/JSONColorValue.md) | -| `background` | [`JSONColorValue`](../type-aliases/JSONColorValue.md) | -| `transform` | [`JSONCellTransform`](JSONCellTransform.md) | diff --git a/api/textmode.export.js/interfaces/JSONObjectRowsCellCollection.md b/api/textmode.export.js/interfaces/JSONObjectRowsCellCollection.md deleted file mode 100644 index dbd94c9f..00000000 --- a/api/textmode.export.js/interfaces/JSONObjectRowsCellCollection.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONObjectRowsCellCollection -description: Row-based cell encoding. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONObjectRowsCellCollection - -# Interface: JSONObjectRowsCellCollection - -Row-based cell encoding. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `encoding` | `"object-rows-v1"` | -| `rows` | [`JSONObjectRowCell`](JSONObjectRowCell.md)[][] | diff --git a/api/textmode.export.js/interfaces/JSONRGBAColor.md b/api/textmode.export.js/interfaces/JSONRGBAColor.md deleted file mode 100644 index 279c2062..00000000 --- a/api/textmode.export.js/interfaces/JSONRGBAColor.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONRGBAColor -description: RGBA color representation used in JSON exports. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / JSONRGBAColor - -# Interface: JSONRGBAColor - -RGBA color representation used in JSON exports. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `r` | `number` | -| `g` | `number` | -| `b` | `number` | -| `a` | `number` | diff --git a/api/textmode.export.js/interfaces/LayerExportOptions.md b/api/textmode.export.js/interfaces/LayerExportOptions.md index 94699d64..f9cd5e72 100644 --- a/api/textmode.export.js/interfaces/LayerExportOptions.md +++ b/api/textmode.export.js/interfaces/LayerExportOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md b/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md deleted file mode 100644 index 288f2385..00000000 --- a/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -layout: doc -editLink: true -title: TextmodeAllDocumentJSON -description: Layer stack document exported by the JSON exporter. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / TextmodeAllDocumentJSON - -# Interface: TextmodeAllDocumentJSON - -Layer stack document exported by the JSON exporter. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `format` | `"textmode.document"` | -| `formatVersion` | `"2.0.0"` | -| `target` | `"all"` | -| `metadata?` | [`JSONExportMetadata`](JSONExportMetadata.md) | -| `canvas` | `object` | -| `canvas.width` | `number` | -| `canvas.height` | `number` | -| `layers` | [`TextmodeDocumentLayer`](TextmodeDocumentLayer.md)[] | diff --git a/api/textmode.export.js/interfaces/TextmodeDocumentLayer.md b/api/textmode.export.js/interfaces/TextmodeDocumentLayer.md deleted file mode 100644 index 7ce78cc3..00000000 --- a/api/textmode.export.js/interfaces/TextmodeDocumentLayer.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: TextmodeDocumentLayer -description: Single layer entry in an all-layers JSON export. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / TextmodeDocumentLayer - -# Interface: TextmodeDocumentLayer - -Single layer entry in an all-layers JSON export. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `id` | `string` | -| `visible` | `boolean` | -| `opacity` | `number` | -| `blendMode` | `string` | -| `offsetX` | `number` | -| `offsetY` | `number` | -| `rotationZ` | `number` | -| `grid` | [`JSONLayerGrid`](JSONLayerGrid.md) | -| `cells` | [`JSONObjectRowsCellCollection`](JSONObjectRowsCellCollection.md) | diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI.md b/api/textmode.export.js/interfaces/TextmodeExportAPI.md index b229ac09..53a097dc 100644 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI.md +++ b/api/textmode.export.js/interfaces/TextmodeExportAPI.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -19,7 +19,103 @@ Runtime export helpers that `ExportPlugin` attaches to the `Textmodifier` instan ## Example - +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16, + plugins: [ExportPlugin], +}); + +const RAMP = ' .:-=+*#%@'; +const energyLayer = t.layers.add({ opacity: 0.9, blendMode: t.BLEND_SCREEN }); +const annotationLayer = t.layers.add({ opacity: 0.95, blendMode: t.BLEND_NORMAL }); +const labelLayer = t.layers.add(); +t.exportOverlay.setDefaults({ format: 'json', json: { target: 'all', pretty: true } }); +t.exportOverlay.show(); +t.exportOverlay.setPosition({ + offsetX: Math.max(8, window.innerWidth - 280), + offsetY: Math.max(8, window.innerHeight - 310), +}); + +function drawText(text, x, y, color = '#a9b7d0') { + t.push(); + t.printAlign('left', 'top'); + t.charColor(color); + t.print(text, x, y); + t.pop(); +} + +t.draw(() => { + t.background('#070b12'); + const halfW = Math.floor(t.grid.cols / 2); + const halfH = Math.floor(t.grid.rows / 2); + for (let y = -halfH; y <= halfH; y++) { + for (let x = -halfW; x <= halfW; x++) { + const ridge = Math.sin(x * 0.17) * 3 + Math.sin(x * 0.07 + 1) * 4; + const depth = (y - ridge + halfH * 0.32) / (halfH * 1.1); + const contour = 0.5 + 0.5 * Math.sin((y - ridge) * 0.72); + const value = depth > 0 ? Math.min(1, 0.3 + depth * 0.45 + contour * 0.25) : 0; + if (value < 0.2) continue; + t.push(); + t.translate(x, y, 0); + t.char(RAMP[Math.min(RAMP.length - 1, Math.floor(value * RAMP.length))]); + t.charColor(value > 0.72 ? '#a9b8c9' : '#53657f'); + t.cellColor('#111b29'); + t.point(); + t.pop(); + } + } +}); + +energyLayer.draw(() => { + t.background(0, 0, 0, 0); + const time = t.frameCount * 0.04; + for (let x = -Math.floor(energyLayer.grid.cols / 2); x < energyLayer.grid.cols / 2; x += 2) { + const y = Math.sin(x * 0.25 + time) * 3 - 1; + t.push(); + t.translate(x, y, 0); + t.char(x % 6 === 0 ? '*' : '~'); + t.charColor(x % 6 === 0 ? '#ffe082' : '#54e6c1'); + t.cellColor(0, 0, 0, 0); + t.point(); + t.pop(); + } +}); + +annotationLayer.draw(() => { + t.background(0, 0, 0, 0); + t.charColor('#e8efff'); + t.printAlign('center', 'center'); + t.print('BASE', -Math.min(Math.floor(annotationLayer.grid.cols / 2) - 5, 15), 6); + t.charColor('#ffd166'); + t.print('ENERGY', Math.min(Math.floor(annotationLayer.grid.cols / 2) - 5, 15), 6); +}); + +window.inspectStackJSON = () => t.toJSON({ target: 'all' }); +window.inspectEnergySVG = () => t.toSVG({ layer: energyLayer, drawMode: 'stroke' }); +window.inspectAnnotationsTXT = () => t.toString({ layer: annotationLayer }); + +labelLayer.draw(() => { + t.clear(); + const left = -Math.floor(t.grid.cols / 2); + const top = -Math.floor(t.grid.rows / 2); + const x = left + 3; + let y = top + 3; + drawText('EXPORTPLUGIN.LAYERTARGETS', x, y++, '#64f2c2'); + drawText('------------------------------------', x, y++, '#345273'); + drawText('CONCEPT: LAYERED OUTPUT', x, y++, '#8fcae8'); + drawText('JSON can save the whole stack.', x, y++); + drawText('SVG and TXT can target one layer.', x, y++); + drawText('------------------------------------', x, y++, '#345273'); + drawText('TARGET: ALL LAYERS', x, y, '#ffd166'); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + ## Properties @@ -29,16 +125,398 @@ Runtime export helpers that `ExportPlugin` attaches to the `Textmodifier` instan ## Methods -| Method | Description | +### copyCanvas() + +```ts +copyCanvas(options?): Promise; +``` + +Copies the current canvas to the user's clipboard as an image. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`ImageExportOptions`](../type-aliases/ImageExportOptions.md) | Export options. | + +#### Returns + +`Promise`\<`void`\> + +#### Example + +```ts +await t.copyCanvas({ format: 'png' }); +``` + + +*** + +### saveCanvas() + +```ts +saveCanvas(options?): Promise; +``` + +Saves the current canvas content to an image file *(`'png'` by default)*. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`ImageExportOptions`](../type-aliases/ImageExportOptions.md) | Export options. | + +#### Returns + +`Promise`\<`void`\> + +#### Example + +```ts +await t.saveCanvas({ format: 'png', filename: 'frame-001' }); +``` + + +*** + +### saveGIF() + +```ts +saveGIF(options?): Promise; +``` + +Records an animated GIF and saves it to disk. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`GIFExportOptions`](../type-aliases/GIFExportOptions.md) | Export options. | + +#### Returns + +`Promise`\<`void`\> + +#### Example + +```ts +await t.saveGIF({ frameCount: 120, frameRate: 30, filename: 'loop' }); +``` + + +*** + +### saveJSON() + +```ts +saveJSON(options?): void; +``` + +Downloads the selected layer or layer stack as a JSON file. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`JSONExportOptions`](../type-aliases/JSONExportOptions.md) | Export options. | + +#### Returns + +`void` + +#### Example + +```ts +t.saveJSON({ filename: 'frame', layer: t.layers.base, pretty: true }); +t.saveJSON({ filename: 'stack', target: 'all' }); +``` + + +*** + +### saveStrings() + +```ts +saveStrings(options?): void; +``` + +Downloads the selected layer's text content as a plain-text file. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`TXTExportOptions`](../type-aliases/TXTExportOptions.md) | Export options. | + +#### Returns + +`void` + +#### Example + +```ts +t.saveStrings({ filename: 'frame', layer: t.layers.base, preserveTrailingSpaces: true }); +``` + + +*** + +### saveSVG() + +```ts +saveSVG(options?): void; +``` + +Downloads the selected layer as an SVG file. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`SVGExportOptions`](../type-aliases/SVGExportOptions.md) | Export options. | + +#### Returns + +`void` + +#### Example + +```ts +t.saveSVG({ filename: 'poster', layer: t.layers.base, includeBackgroundRectangles: true }); +``` + + +*** + +### saveVideo() + +```ts +saveVideo(options?): Promise; +``` + +Captures a video and saves it to disk *(`'mp4'` by default)*. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`VideoExportOptions`](../type-aliases/VideoExportOptions.md) | Export options. | + +#### Returns + +`Promise`\<`void`\> + +#### Example + +```ts +await t.saveVideo({ frameCount: 240, frameRate: 60, filename: 'capture' }); +await t.saveVideo({ + format: 'webm', + bitrate: 'high', + bitrateMode: 'variable', + latencyMode: 'quality', + keyFrameInterval: 2, + frameCount: 240, + filename: 'capture', +}); +``` + + +*** + +### toGIFBlob() + +```ts +toGIFBlob(options?): Promise; +``` + +Generates an animated GIF blob without downloading it. + +#### Parameters + +| Parameter | Type | | ------ | ------ | -| [saveCanvas](TextmodeExportAPI/methods/saveCanvas.md) | Saves the current canvas content to an image file *(`'png'` by default)*. | -| [copyCanvas](TextmodeExportAPI/methods/copyCanvas.md) | Copies the current canvas to the user's clipboard as an image. | -| [saveSVG](TextmodeExportAPI/methods/saveSVG.md) | Downloads the selected layer as an SVG file. | -| [saveStrings](TextmodeExportAPI/methods/saveStrings.md) | Downloads the selected layer's text content as a plain-text file. | -| [toSVG](TextmodeExportAPI/methods/toSVG.md) | Generates SVG markup for the selected layer. | -| [toString](TextmodeExportAPI/methods/toString.md) | Produces the selected layer's text content as a string. | -| [toJSON](TextmodeExportAPI/methods/toJSON.md) | Produces the selected layer or layer stack as structured JSON data. | -| [toJSONString](TextmodeExportAPI/methods/toJSONString.md) | Produces the selected layer or layer stack as a JSON string. | -| [saveJSON](TextmodeExportAPI/methods/saveJSON.md) | Downloads the selected layer or layer stack as a JSON file. | -| [saveGIF](TextmodeExportAPI/methods/saveGIF.md) | Records an animated GIF and saves it to disk. | -| [saveVideo](TextmodeExportAPI/methods/saveVideo.md) | Captures a video and saves it to disk *(`'mp4'` by default)*. | +| `options?` | [`GIFExportOptions`](../type-aliases/GIFExportOptions.md) | + +#### Returns + +`Promise`\<`Blob`\> + +#### Example + +```ts +const blob = await t.toGIFBlob({ frameCount: 90, frameRate: 30 }); +``` + + +*** + +### toImageBlob() + +```ts +toImageBlob(options?): Promise; +``` + +Generates the current canvas as an image blob without downloading it. + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `options?` | [`ImageExportOptions`](../type-aliases/ImageExportOptions.md) | + +#### Returns + +`Promise`\<`Blob`\> + +#### Example + +```ts +const blob = await t.toImageBlob({ format: 'webp', scale: 2 }); +``` + + +*** + +### toJSON() + +```ts +toJSON(options?): TextmodeDocumentJSON; +``` + +Produces the selected layer or layer stack as structured JSON data. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`JSONExportOptions`](../type-aliases/JSONExportOptions.md) | Export options. | + +#### Returns + +[`TextmodeDocumentJSON`](../type-aliases/TextmodeDocumentJSON.md) + +The JSON document representing the selected layer or layer stack. + +#### Example + +```ts +const layer = t.toJSON({ layer: t.layers.base, colorMode: 'hex', includeMetadata: true }); +const stack = t.toJSON({ target: 'all' }); +``` + + +*** + +### toJSONString() + +```ts +toJSONString(options?): string; +``` + +Produces the selected layer or layer stack as a JSON string. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`JSONExportOptions`](../type-aliases/JSONExportOptions.md) | Export options. | + +#### Returns + +`string` + +Serialized JSON string for the selected layer or layer stack. + +#### Example + +```ts +const json = t.toJSONString({ layer: t.layers.base, pretty: false, colorMode: 'hex' }); +const stackJson = t.toJSONString({ target: 'all' }); +``` + + +*** + +### toString() + +```ts +toString(options?): string; +``` + +Produces the selected layer's text content as a string. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`TXTExportOptions`](../type-aliases/TXTExportOptions.md) | Export options. | + +#### Returns + +`string` + +The textual representation of the artwork. + +#### Example + +```ts +const text = t.toString({ layer: t.layers.base, preserveTrailingSpaces: false }); +``` + + +*** + +### toSVG() + +```ts +toSVG(options?): string; +``` + +Generates SVG markup for the selected layer. + +#### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`SVGExportOptions`](../type-aliases/SVGExportOptions.md) | Export options. | + +#### Returns + +`string` + +The SVG content representing the artwork. + +#### Example + +```ts +const svg = t.toSVG({ layer: t.layers.base, drawMode: 'stroke', strokeWidth: 1.5 }); +``` + + +*** + +### toVideoBlob() + +```ts +toVideoBlob(options?): Promise; +``` + +Generates a video blob without downloading it. + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `options?` | [`VideoExportOptions`](../type-aliases/VideoExportOptions.md) | + +#### Returns + +`Promise`\<`Blob`\> + +#### Example + +```ts +const blob = await t.toVideoBlob({ format: 'webm', frameCount: 120, frameRate: 30 }); +``` + diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/copyCanvas.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/copyCanvas.md deleted file mode 100644 index 3e89333e..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/copyCanvas.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: copyCanvas -description: Copies the current canvas to the user's clipboard as an image. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / copyCanvas - -# Method: copyCanvas() - -```ts -copyCanvas(options?): Promise; -``` - -Copies the current canvas to the user's clipboard as an image. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`ImageExportOptions`](../../../type-aliases/ImageExportOptions.md) | Export options. | - -## Returns - -`Promise`\<`void`\> - -## Example - -```ts -await t.copyCanvas({ format: 'png' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveCanvas.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveCanvas.md deleted file mode 100644 index 89524845..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveCanvas.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: saveCanvas -description: Saves the current canvas content to an image file *('png' by default)*. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveCanvas - -# Method: saveCanvas() - -```ts -saveCanvas(options?): Promise; -``` - -Saves the current canvas content to an image file *(`'png'` by default)*. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`ImageExportOptions`](../../../type-aliases/ImageExportOptions.md) | Export options. | - -## Returns - -`Promise`\<`void`\> - -## Example - -```ts -await t.saveCanvas({ format: 'png', filename: 'frame-001' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveGIF.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveGIF.md deleted file mode 100644 index d909738e..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveGIF.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: saveGIF -description: Records an animated GIF and saves it to disk. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveGIF - -# Method: saveGIF() - -```ts -saveGIF(options?): Promise; -``` - -Records an animated GIF and saves it to disk. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`GIFExportOptions`](../../../type-aliases/GIFExportOptions.md) | Export options. | - -## Returns - -`Promise`\<`void`\> - -## Example - -```ts -await t.saveGIF({ frameCount: 120, frameRate: 30, filename: 'loop' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveJSON.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveJSON.md deleted file mode 100644 index c21fbed3..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveJSON.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -layout: doc -editLink: true -title: saveJSON -description: Downloads the selected layer or layer stack as a JSON file. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveJSON - -# Method: saveJSON() - -```ts -saveJSON(options?): void; -``` - -Downloads the selected layer or layer stack as a JSON file. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`JSONExportOptions`](../../../type-aliases/JSONExportOptions.md) | Export options. | - -## Returns - -`void` - -## Example - -```ts -t.saveJSON({ filename: 'frame', layer: t.layers.base, pretty: true }); -t.saveJSON({ filename: 'stack', target: 'all' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveSVG.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveSVG.md deleted file mode 100644 index 43de4506..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveSVG.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: saveSVG -description: Downloads the selected layer as an SVG file. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveSVG - -# Method: saveSVG() - -```ts -saveSVG(options?): void; -``` - -Downloads the selected layer as an SVG file. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`SVGExportOptions`](../../../type-aliases/SVGExportOptions.md) | Export options. | - -## Returns - -`void` - -## Example - -```ts -t.saveSVG({ filename: 'poster', layer: t.layers.base, includeBackgroundRectangles: true }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveStrings.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveStrings.md deleted file mode 100644 index 533f7ab1..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveStrings.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -layout: doc -editLink: true -title: saveStrings -description: Downloads the selected layer's text content as a plain-text file. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveStrings - -# Method: saveStrings() - -```ts -saveStrings(options?): void; -``` - -Downloads the selected layer's text content as a plain-text file. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`TXTExportOptions`](../../../type-aliases/TXTExportOptions.md) | Export options. | - -## Returns - -`void` - -## Example - -```ts -t.saveStrings({ filename: 'frame', layer: t.layers.base, preserveTrailingSpaces: true }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md deleted file mode 100644 index 333566f0..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -layout: doc -editLink: true -title: saveVideo -description: Captures a video and saves it to disk *('mp4' by default)*. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / saveVideo - -# Method: saveVideo() - -```ts -saveVideo(options?): Promise; -``` - -Captures a video and saves it to disk *(`'mp4'` by default)*. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`VideoExportOptions`](../../../type-aliases/VideoExportOptions.md) | Export options. | - -## Returns - -`Promise`\<`void`\> - -## Example - -```ts -await t.saveVideo({ frameCount: 240, frameRate: 60, filename: 'capture' }); -await t.saveVideo({ - format: 'webm', - bitrate: 'high', - bitrateMode: 'variable', - latencyMode: 'quality', - keyFrameInterval: 2, - frameCount: 240, - filename: 'capture', -}); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSON.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSON.md deleted file mode 100644 index 62b178b7..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSON.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -layout: doc -editLink: true -title: toJSON -description: Produces the selected layer or layer stack as structured JSON data. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / toJSON - -# Method: toJSON() - -```ts -toJSON(options?): TextmodeDocumentJSON; -``` - -Produces the selected layer or layer stack as structured JSON data. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`JSONExportOptions`](../../../type-aliases/JSONExportOptions.md) | Export options. | - -## Returns - -[`TextmodeDocumentJSON`](../../../type-aliases/TextmodeDocumentJSON.md) - -The JSON document representing the selected layer or layer stack. - -## Example - -```ts -const layer = t.toJSON({ layer: t.layers.base, colorMode: 'hex', includeMetadata: true }); -const stack = t.toJSON({ target: 'all' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSONString.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSONString.md deleted file mode 100644 index 1be21799..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSONString.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -layout: doc -editLink: true -title: toJSONString -description: Produces the selected layer or layer stack as a JSON string. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / toJSONString - -# Method: toJSONString() - -```ts -toJSONString(options?): string; -``` - -Produces the selected layer or layer stack as a JSON string. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`JSONExportOptions`](../../../type-aliases/JSONExportOptions.md) | Export options. | - -## Returns - -`string` - -Serialized JSON string for the selected layer or layer stack. - -## Example - -```ts -const json = t.toJSONString({ layer: t.layers.base, pretty: false, colorMode: 'hex' }); -const stackJson = t.toJSONString({ target: 'all' }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toSVG.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toSVG.md deleted file mode 100644 index 11f611b2..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toSVG.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -layout: doc -editLink: true -title: toSVG -description: Generates SVG markup for the selected layer. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / toSVG - -# Method: toSVG() - -```ts -toSVG(options?): string; -``` - -Generates SVG markup for the selected layer. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`SVGExportOptions`](../../../type-aliases/SVGExportOptions.md) | Export options. | - -## Returns - -`string` - -The SVG content representing the artwork. - -## Example - -```ts -const svg = t.toSVG({ layer: t.layers.base, drawMode: 'stroke', strokeWidth: 1.5 }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toString.md b/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toString.md deleted file mode 100644 index 4f301410..00000000 --- a/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toString.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -layout: doc -editLink: true -title: toString -description: Produces the selected layer's text content as a string. -category: Methods -api: true -owner: TextmodeExportAPI -kind: Method -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../../../index.md) / [TextmodeExportAPI](../../TextmodeExportAPI.md) / toString - -# Method: toString() - -```ts -toString(options?): string; -``` - -Produces the selected layer's text content as a string. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `options?` | [`TXTExportOptions`](../../../type-aliases/TXTExportOptions.md) | Export options. | - -## Returns - -`string` - -The textual representation of the artwork. - -## Example - -```ts -const text = t.toString({ layer: t.layers.base, preserveTrailingSpaces: false }); -``` - diff --git a/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md b/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md deleted file mode 100644 index 41f693b7..00000000 --- a/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: doc -editLink: true -title: TextmodeSelectedDocumentJSON -description: Selected-layer document exported by the JSON exporter. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / TextmodeSelectedDocumentJSON - -# Interface: TextmodeSelectedDocumentJSON - -Selected-layer document exported by the JSON exporter. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `format` | `"textmode.document"` | -| `formatVersion` | `"2.0.0"` | -| `target` | `"selected"` | -| `metadata?` | [`JSONExportMetadata`](JSONExportMetadata.md) | -| `canvas` | `object` | -| `canvas.width` | `number` | -| `canvas.height` | `number` | -| `grid` | [`JSONLayerGrid`](JSONLayerGrid.md) | -| `layer` | [`TextmodeSelectedDocumentLayer`](TextmodeSelectedDocumentLayer.md) | diff --git a/api/textmode.export.js/interfaces/TextmodeSelectedDocumentLayer.md b/api/textmode.export.js/interfaces/TextmodeSelectedDocumentLayer.md deleted file mode 100644 index 1e57dadf..00000000 --- a/api/textmode.export.js/interfaces/TextmodeSelectedDocumentLayer.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: doc -editLink: true -title: TextmodeSelectedDocumentLayer -description: Selected-layer entry in a JSON document export. -category: Interfaces -api: true -kind: Interface -ecosystem: textmode.js -lastModified: 2026-07-31 -isInterface: true ---- - -[textmode.export.js](../index.md) / TextmodeSelectedDocumentLayer - -# Interface: TextmodeSelectedDocumentLayer - -Selected-layer entry in a JSON document export. - - -## Properties - -| Property | Type | -| ------ | ------ | -| `id` | `string` | -| `cells` | [`JSONObjectRowsCellCollection`](JSONObjectRowsCellCollection.md) | diff --git a/api/textmode.export.js/type-aliases/ExportDefaults.md b/api/textmode.export.js/type-aliases/ExportDefaults.md index 72345600..03bb7695 100644 --- a/api/textmode.export.js/type-aliases/ExportDefaults.md +++ b/api/textmode.export.js/type-aliases/ExportDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / ExportDefaults @@ -19,13 +19,13 @@ type ExportDefaults = object; ``` Per-format default options used to seed the overlay UI inputs at mount time -and after a [ExportOverlayController.resetDefaults](../interfaces/ExportOverlayController/methods/resetDefaults.md) call. +and after a [ExportOverlayController.resetDefaults](../interfaces/ExportOverlayController.md#resetdefaults) call. Each sub-object contains the library-chosen defaults for the fields that the overlay exposes. Top-level `format` controls which export format is selected in the overlay. You can read and override them at runtime via -[ExportOverlayController.getDefaults](../interfaces/ExportOverlayController/methods/getDefaults.md) and -[ExportOverlayController.setDefaults](../interfaces/ExportOverlayController/methods/setDefaults.md). +[ExportOverlayController.getDefaults](../interfaces/ExportOverlayController.md#getdefaults) and +[ExportOverlayController.setDefaults](../interfaces/ExportOverlayController.md#setdefaults). ## Properties @@ -41,26 +41,26 @@ Export format selected by default in the overlay. *** -### txt +### gif ```ts -txt: TXTOverlayDefaults; +gif: GIFOverlayDefaults; ``` *** -### json +### image ```ts -json: JSONOverlayDefaults; +image: ImageOverlayDefaults; ``` *** -### image +### json ```ts -image: ImageOverlayDefaults; +json: JSONOverlayDefaults; ``` *** @@ -73,10 +73,10 @@ svg: SVGOverlayDefaults; *** -### gif +### txt ```ts -gif: GIFOverlayDefaults; +txt: TXTOverlayDefaults; ``` *** diff --git a/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md b/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md index c1ee9ac8..ada18f6f 100644 --- a/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md +++ b/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / ExportDefaultsPatch @@ -18,7 +18,7 @@ lastModified: 2026-07-31 type ExportDefaultsPatch = object & { [K in Exclude]?: Partial }; ``` -Partial patch accepted by [ExportOverlayController.setDefaults](../interfaces/ExportOverlayController/methods/setDefaults.md). +Partial patch accepted by [ExportOverlayController.setDefaults](../interfaces/ExportOverlayController.md#setdefaults). Every supplied per-format sub-object is deep-merged into the corresponding format's curated defaults. Top-level `format` changes the overlay's selected diff --git a/api/textmode.export.js/type-aliases/GIFExportOptions.md b/api/textmode.export.js/type-aliases/GIFExportOptions.md index da69c465..e3c1a7ce 100644 --- a/api/textmode.export.js/type-aliases/GIFExportOptions.md +++ b/api/textmode.export.js/type-aliases/GIFExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / GIFExportOptions @@ -56,17 +56,34 @@ Target frame rate for the export, in frames per second. Defaults to `60`. *** -### scale? +### onProgress? ```ts -optional scale?: number; +optional onProgress?: (progress) => void; ``` -Scale factor for the output image. +Progress callback invoked throughout the recording lifecycle. -`1.0` = original size, `2.0` = double size, `0.5` = half size. +#### Parameters -Defaults to `1.0`. +| Parameter | Type | +| ------ | ------ | +| `progress` | [`GIFExportProgress`](GIFExportProgress.md) | + +#### Returns + +`void` + + +*** + +### prepareFrame? + +```ts +optional prepareFrame?: PrepareExportFrame; +``` + +Prepares external media before each deterministic frame is redrawn. *** @@ -82,21 +99,26 @@ GIF loop count. 0 = loop forever. Defaults to `0`. *** -### onProgress? +### scale? ```ts -optional onProgress?: (progress) => void; +optional scale?: number; ``` -Progress callback invoked throughout the recording lifecycle. +Scale factor for the output image. -#### Parameters +`1.0` = original size, `2.0` = double size, `0.5` = half size. -| Parameter | Type | -| ------ | ------ | -| `progress` | [`GIFExportProgress`](GIFExportProgress.md) | +Defaults to `1.0`. -#### Returns -`void` +*** + +### signal? + +```ts +optional signal?: AbortSignal; +``` + +Abort signal for cancelling capture or encoding. diff --git a/api/textmode.export.js/type-aliases/GIFExportProgress.md b/api/textmode.export.js/type-aliases/GIFExportProgress.md index 2f8c7e84..78c368b7 100644 --- a/api/textmode.export.js/type-aliases/GIFExportProgress.md +++ b/api/textmode.export.js/type-aliases/GIFExportProgress.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / GIFExportProgress @@ -23,44 +23,44 @@ Progress information emitted during the GIF export process. ## Properties -### state +### frameIndex? ```ts -state: "idle" | "recording" | "encoding" | "completed" | "error"; +optional frameIndex?: number; ``` -Current state of the recording process. +Number of frames that have been recorded so far. *** -### frameIndex? +### message? ```ts -optional frameIndex?: number; +optional message?: string; ``` -Number of frames that have been recorded so far. +Optional status message for UI consumption. *** -### totalFrames? +### state ```ts -optional totalFrames?: number; +state: "idle" | "recording" | "encoding" | "completed" | "error"; ``` -Total number of frames planned for the recording. +Current state of the recording process. *** -### message? +### totalFrames? ```ts -optional message?: string; +optional totalFrames?: number; ``` -Optional status message for UI consumption. +Total number of frames planned for the recording. diff --git a/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md b/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md index a327936a..3d045c68 100644 --- a/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / GIFOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/ImageExportOptions.md b/api/textmode.export.js/type-aliases/ImageExportOptions.md index 3b5289d8..0af11905 100644 --- a/api/textmode.export.js/type-aliases/ImageExportOptions.md +++ b/api/textmode.export.js/type-aliases/ImageExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / ImageExportOptions diff --git a/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md b/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md index 94afe3b4..696814d3 100644 --- a/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / ImageOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/JSONCellCollection.md b/api/textmode.export.js/type-aliases/JSONCellCollection.md deleted file mode 100644 index ad8379a2..00000000 --- a/api/textmode.export.js/type-aliases/JSONCellCollection.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONCellCollection -description: Supported JSON cell collection variants. -category: Type Aliases -api: true -kind: TypeAlias -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../index.md) / JSONCellCollection - -# Type Alias: JSONCellCollection - -```ts -type JSONCellCollection = JSONObjectRowsCellCollection; -``` - -Supported JSON cell collection variants. - diff --git a/api/textmode.export.js/type-aliases/JSONColorValue.md b/api/textmode.export.js/type-aliases/JSONColorValue.md deleted file mode 100644 index e306c46c..00000000 --- a/api/textmode.export.js/type-aliases/JSONColorValue.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONColorValue -description: Color value used in the exported JSON document. -category: Type Aliases -api: true -kind: TypeAlias -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../index.md) / JSONColorValue - -# Type Alias: JSONColorValue - -```ts -type JSONColorValue = string | JSONRGBAColor; -``` - -Color value used in the exported JSON document. - diff --git a/api/textmode.export.js/type-aliases/JSONDocumentFormat.md b/api/textmode.export.js/type-aliases/JSONDocumentFormat.md deleted file mode 100644 index 8f0fa62c..00000000 --- a/api/textmode.export.js/type-aliases/JSONDocumentFormat.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONDocumentFormat -description: Canonical JSON document format identifier. -category: Type Aliases -api: true -kind: TypeAlias -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../index.md) / JSONDocumentFormat - -# Type Alias: JSONDocumentFormat - -```ts -type JSONDocumentFormat = "textmode.document"; -``` - -Canonical JSON document format identifier. - diff --git a/api/textmode.export.js/type-aliases/JSONDocumentVersion.md b/api/textmode.export.js/type-aliases/JSONDocumentVersion.md deleted file mode 100644 index ba80221d..00000000 --- a/api/textmode.export.js/type-aliases/JSONDocumentVersion.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: doc -editLink: true -title: JSONDocumentVersion -description: Canonical JSON document format version. -category: Type Aliases -api: true -kind: TypeAlias -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../index.md) / JSONDocumentVersion - -# Type Alias: JSONDocumentVersion - -```ts -type JSONDocumentVersion = "2.0.0"; -``` - -Canonical JSON document format version. - diff --git a/api/textmode.export.js/type-aliases/JSONExportColorMode.md b/api/textmode.export.js/type-aliases/JSONExportColorMode.md index 29afe268..5cbbd115 100644 --- a/api/textmode.export.js/type-aliases/JSONExportColorMode.md +++ b/api/textmode.export.js/type-aliases/JSONExportColorMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / JSONExportColorMode diff --git a/api/textmode.export.js/type-aliases/JSONExportOptions.md b/api/textmode.export.js/type-aliases/JSONExportOptions.md index d05496de..d724ee3c 100644 --- a/api/textmode.export.js/type-aliases/JSONExportOptions.md +++ b/api/textmode.export.js/type-aliases/JSONExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / JSONExportOptions @@ -24,9 +24,9 @@ Options for exporting the textmode content to JSON format. | Name | Type | Description | | ------ | ------ | ------ | -| `target?` | [`JSONExportTarget`](JSONExportTarget.md) | Scope of the JSON export. Use `'selected'` to export one layer, or `'all'` to export the base layer and every user-created layer. Defaults to `'selected'`. | -| `filename?` | `string` | The filename to save the JSON file as. If not provided, a default filename is used. | -| `pretty?` | `boolean` \| `number` | Pretty-print the generated JSON. When set to `true`, output uses two-space indentation. When set to a number, that value is used as indentation width. When `false`, the output is minified. Defaults to `true`. | | `colorMode?` | [`JSONExportColorMode`](JSONExportColorMode.md) | Color representation used for foreground and background values. Defaults to `'hex'`. | +| `filename?` | `string` | The filename to save the JSON file as. If not provided, a default filename is used. | | `includeMetadata?` | `boolean` | Whether to include export metadata such as timestamp and generator details. Defaults to `true`. | +| `pretty?` | `boolean` \| `number` | Pretty-print the generated JSON. When set to `true`, output uses two-space indentation. When set to a number, that value is used as indentation width. When `false`, the output is minified. Defaults to `true`. | +| `target?` | [`JSONExportTarget`](JSONExportTarget.md) | Scope of the JSON export. Use `'selected'` to export one layer, or `'all'` to export the base layer and every user-created layer. Defaults to `'selected'`. | diff --git a/api/textmode.export.js/type-aliases/JSONExportTarget.md b/api/textmode.export.js/type-aliases/JSONExportTarget.md index 5b524c97..fd5d0944 100644 --- a/api/textmode.export.js/type-aliases/JSONExportTarget.md +++ b/api/textmode.export.js/type-aliases/JSONExportTarget.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / JSONExportTarget diff --git a/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md b/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md index e4bf6102..b99503be 100644 --- a/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / JSONOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/SVGExportOptions.md b/api/textmode.export.js/type-aliases/SVGExportOptions.md index 6b41656c..e8ff4102 100644 --- a/api/textmode.export.js/type-aliases/SVGExportOptions.md +++ b/api/textmode.export.js/type-aliases/SVGExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / SVGExportOptions @@ -24,8 +24,8 @@ Options for exporting the textmode content to SVG format. | Name | Type | Description | | ------ | ------ | ------ | +| `drawMode?` | `"fill"` \| `"stroke"` | The drawing mode for ASCII characters. When set to `'fill'`, characters are rendered as filled shapes. When set to `'stroke'`, characters are rendered as outlines. Defaults to `'fill'`. | | `filename?` | `string` | The filename to save the SVG file as. If not provided, a default filename is used. | | `includeBackgroundRectangles?` | `boolean` | Whether to include cell background rectangles in the SVG output. When `false`, only the character paths are included. Defaults to `true`. | -| `drawMode?` | `"fill"` \| `"stroke"` | The drawing mode for ASCII characters. When set to `'fill'`, characters are rendered as filled shapes. When set to `'stroke'`, characters are rendered as outlines. Defaults to `'fill'`. | | `strokeWidth?` | `number` | The stroke width to use when drawMode is set to `'stroke'`. Defaults to `1.0`. | diff --git a/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md b/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md index ad31fc0f..4aad4178 100644 --- a/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / SVGOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/TXTExportOptions.md b/api/textmode.export.js/type-aliases/TXTExportOptions.md index 33922ec7..10c90caa 100644 --- a/api/textmode.export.js/type-aliases/TXTExportOptions.md +++ b/api/textmode.export.js/type-aliases/TXTExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / TXTExportOptions @@ -24,7 +24,7 @@ Options for exporting the textmode content to TXT format. | Name | Type | Description | | ------ | ------ | ------ | +| `emptyCharacter?` | `string` | Character to use for empty cells *(when no character is rendered in it)*. Defaults to space `' '`. | | `filename?` | `string` | The filename to save the TXT file as. If not provided, a default filename is used. | | `preserveTrailingSpaces?` | `boolean` | Whether to preserve trailing spaces on each line. When `false`, trailing spaces are trimmed from each line. Defaults to `false`. | -| `emptyCharacter?` | `string` | Character to use for empty cells *(when no character is rendered in it)*. Defaults to space `' '`. | diff --git a/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md b/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md index 59592f48..b0b2daf7 100644 --- a/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / TXTOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md b/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md index 04b94b33..bd2a3219 100644 --- a/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md +++ b/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / TextmodeDocumentJSON @@ -15,9 +15,7 @@ lastModified: 2026-07-31 # Type Alias: TextmodeDocumentJSON ```ts -type TextmodeDocumentJSON = - | TextmodeSelectedDocumentJSON - | TextmodeAllDocumentJSON; +type TextmodeDocumentJSON = TextmodeSelectedDocumentJSON | TextmodeAllDocumentJSON; ``` JSON document exported by the JSON exporter. diff --git a/api/textmode.export.js/type-aliases/VideoBitrateMode.md b/api/textmode.export.js/type-aliases/VideoBitrateMode.md index beb1547e..fba1387a 100644 --- a/api/textmode.export.js/type-aliases/VideoBitrateMode.md +++ b/api/textmode.export.js/type-aliases/VideoBitrateMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoBitrateMode diff --git a/api/textmode.export.js/type-aliases/VideoBitratePreset.md b/api/textmode.export.js/type-aliases/VideoBitratePreset.md index 90a1b171..ebf8d753 100644 --- a/api/textmode.export.js/type-aliases/VideoBitratePreset.md +++ b/api/textmode.export.js/type-aliases/VideoBitratePreset.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoBitratePreset diff --git a/api/textmode.export.js/type-aliases/VideoExportErrorCode.md b/api/textmode.export.js/type-aliases/VideoExportErrorCode.md deleted file mode 100644 index e6d8f736..00000000 --- a/api/textmode.export.js/type-aliases/VideoExportErrorCode.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: doc -editLink: true -title: VideoExportErrorCode -description: VideoExportErrorCode type definition and usage in textmode.export.js. -category: Type Aliases -api: true -kind: TypeAlias -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.export.js](../index.md) / VideoExportErrorCode - -# Type Alias: VideoExportErrorCode - -```ts -type VideoExportErrorCode = - | "VIDEO_EXPORT_UNSUPPORTED" - | "VIDEO_CODEC_UNSUPPORTED" - | "VIDEO_EXPORT_ABORTED" - | "VIDEO_EXPORT_TIMEOUT" - | "VIDEO_EXPORT_FAILED" - | "VIDEO_TRANSPARENCY_UNSUPPORTED"; -``` diff --git a/api/textmode.export.js/type-aliases/VideoExportFormat.md b/api/textmode.export.js/type-aliases/VideoExportFormat.md index 414a1c0a..a91dd360 100644 --- a/api/textmode.export.js/type-aliases/VideoExportFormat.md +++ b/api/textmode.export.js/type-aliases/VideoExportFormat.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoExportFormat diff --git a/api/textmode.export.js/type-aliases/VideoExportOptions.md b/api/textmode.export.js/type-aliases/VideoExportOptions.md index caa392e9..41e8e26a 100644 --- a/api/textmode.export.js/type-aliases/VideoExportOptions.md +++ b/api/textmode.export.js/type-aliases/VideoExportOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoExportOptions @@ -23,89 +23,86 @@ Options for exporting the textmode content to video format. ## Properties -### filename? +### bitrate? ```ts -optional filename?: string; +optional bitrate?: number | VideoBitratePreset; ``` -Target filename without extension. Defaults to an auto-generated value. +Target bitrate in bits per second or a bitrate preset. Defaults to `'medium'`. + +Bitrate controls how much encoded data is available per second of video. Higher values can preserve more detail +in noisy or fast-changing sketches, but create larger files. Presets are resolved from the export dimensions and +frame rate; numeric values are passed directly to the encoder. *** -### format? +### bitrateMode? ```ts -optional format?: VideoExportFormat; +optional bitrateMode?: VideoBitrateMode; ``` -Video container format. Defaults to `'mp4'`. +Encoder bitrate allocation mode. Defaults to `'variable'`. + +Use `'variable'` for most exports so simple frames can compress efficiently and complex frames can receive more +bits. Use `'constant'` only when a steadier data rate is more important than compression efficiency. *** -### frameCount? +### debugLogging? ```ts -optional frameCount?: number; +optional debugLogging?: boolean; ``` -Desired total number of frames to capture. Defaults to `300`. +Enables verbose logging. Defaults to `false`. *** -### frameRate? +### filename? ```ts -optional frameRate?: number; +optional filename?: string; ``` -Target frame rate for the export, in frames per second. Defaults to `60`. +Target filename without extension. Defaults to an auto-generated value. *** -### bitrate? +### format? ```ts -optional bitrate?: number | VideoBitratePreset; +optional format?: VideoExportFormat; ``` -Target bitrate in bits per second or a bitrate preset. Defaults to `'medium'`. - -Bitrate controls how much encoded data is available per second of video. Higher values can preserve more detail -in noisy or fast-changing sketches, but create larger files. Presets are resolved from the export dimensions and -frame rate; numeric values are passed directly to the encoder. +Video container format. Defaults to `'mp4'`. *** -### bitrateMode? +### frameCount? ```ts -optional bitrateMode?: VideoBitrateMode; +optional frameCount?: number; ``` -Encoder bitrate allocation mode. Defaults to `'variable'`. - -Use `'variable'` for most exports so simple frames can compress efficiently and complex frames can receive more -bits. Use `'constant'` only when a steadier data rate is more important than compression efficiency. +Desired total number of frames to capture. Defaults to `300`. *** -### latencyMode? +### frameRate? ```ts -optional latencyMode?: VideoLatencyMode; +optional frameRate?: number; ``` -Encoder latency mode. Defaults to `'quality'`. - -Use `'quality'` for deterministic exports; it prioritizes completed output and avoids dropped frames. Use -`'realtime'` only for low-latency use cases where dropped frames are acceptable. +Target frame rate for the export, in frames per second. Defaults to `60`. *** @@ -139,65 +136,79 @@ Use `0` to request every frame as a key frame. *** -### pixelDensity? +### latencyMode? ```ts -optional pixelDensity?: number; +optional latencyMode?: VideoLatencyMode; ``` -Pixel density used during export. Defaults to `1` so video dimensions match the live canvas. +Encoder latency mode. Defaults to `'quality'`. + +Use `'quality'` for deterministic exports; it prioritizes completed output and avoids dropped frames. Use +`'realtime'` only for low-latency use cases where dropped frames are acceptable. *** -### signal? +### onProgress? ```ts -optional signal?: AbortSignal; +optional onProgress?: (progress) => void; ``` -Abort signal for cancelling an in-progress export. +Progress callback invoked throughout the recording lifecycle. + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `progress` | [`VideoExportProgress`](VideoExportProgress.md) | + +#### Returns + +`void` *** -### transparent? +### pixelDensity? ```ts -optional transparent?: boolean; +optional pixelDensity?: number; ``` -When true, attempts to preserve alpha data in WebM recordings. MP4 exports reject this option. +Pixel density used during export. Defaults to `1` so video dimensions match the live canvas. *** -### onProgress? +### prepareFrame? ```ts -optional onProgress?: (progress) => void; +optional prepareFrame?: PrepareExportFrame; ``` -Progress callback invoked throughout the recording lifecycle. +Prepares external media before each deterministic frame is redrawn. -#### Parameters -| Parameter | Type | -| ------ | ------ | -| `progress` | [`VideoExportProgress`](VideoExportProgress.md) | +*** -#### Returns +### signal? -`void` +```ts +optional signal?: AbortSignal; +``` + +Abort signal for cancelling an in-progress export. *** -### debugLogging? +### transparent? ```ts -optional debugLogging?: boolean; +optional transparent?: boolean; ``` -Enables verbose logging. Defaults to `false`. +When true, attempts to preserve alpha data in WebM recordings. MP4 exports reject this option. diff --git a/api/textmode.export.js/type-aliases/VideoExportPhase.md b/api/textmode.export.js/type-aliases/VideoExportPhase.md index c5d218dd..8dc955ba 100644 --- a/api/textmode.export.js/type-aliases/VideoExportPhase.md +++ b/api/textmode.export.js/type-aliases/VideoExportPhase.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoExportPhase diff --git a/api/textmode.export.js/type-aliases/VideoExportProgress.md b/api/textmode.export.js/type-aliases/VideoExportProgress.md index 796472b9..de47b483 100644 --- a/api/textmode.export.js/type-aliases/VideoExportProgress.md +++ b/api/textmode.export.js/type-aliases/VideoExportProgress.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoExportProgress @@ -23,77 +23,77 @@ Progress information emitted during the video export process. ## Properties -### state +### frame? ```ts -state: VideoRecordingState; +optional frame?: number; ``` -Current state of the recording process. +Alias for [frameIndex](#frameindex). Prefer this field in new code. *** -### phase? +### frameIndex? ```ts -optional phase?: VideoExportPhase; +optional frameIndex?: number; ``` -Current export phase for newer progress UIs. +Number of frames that have been recorded so far. *** -### frameIndex? +### message? ```ts -optional frameIndex?: number; +optional message?: string; ``` -Number of frames that have been recorded so far. +Optional status message for UI consumption. *** -### frame? +### phase? ```ts -optional frame?: number; +optional phase?: VideoExportPhase; ``` -Alias for [frameIndex](#frameindex). Prefer this field in new code. +Current export phase for newer progress UIs. *** -### totalFrames? +### progress? ```ts -optional totalFrames?: number; +optional progress?: number; ``` -Total number of frames planned for the recording. +Export completion ratio between `0` and `1`. *** -### progress? +### state ```ts -optional progress?: number; +state: VideoRecordingState; ``` -Export completion ratio between `0` and `1`. +Current state of the recording process. *** -### message? +### totalFrames? ```ts -optional message?: string; +optional totalFrames?: number; ``` -Optional status message for UI consumption. +Total number of frames planned for the recording. diff --git a/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md b/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md index 1d28948c..6f9162d1 100644 --- a/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md +++ b/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoHardwareAcceleration diff --git a/api/textmode.export.js/type-aliases/VideoLatencyMode.md b/api/textmode.export.js/type-aliases/VideoLatencyMode.md index e0ba39d2..74f2de83 100644 --- a/api/textmode.export.js/type-aliases/VideoLatencyMode.md +++ b/api/textmode.export.js/type-aliases/VideoLatencyMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoLatencyMode diff --git a/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md b/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md index a984c09a..d842e3d4 100644 --- a/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md +++ b/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoOverlayDefaults diff --git a/api/textmode.export.js/type-aliases/VideoRecordingState.md b/api/textmode.export.js/type-aliases/VideoRecordingState.md index f2d4f92a..6865b45c 100644 --- a/api/textmode.export.js/type-aliases/VideoRecordingState.md +++ b/api/textmode.export.js/type-aliases/VideoRecordingState.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / VideoRecordingState diff --git a/api/textmode.export.js/typedoc-sidebar.json b/api/textmode.export.js/typedoc-sidebar.json index 1d4d08b6..3de9571a 100644 --- a/api/textmode.export.js/typedoc-sidebar.json +++ b/api/textmode.export.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Interfaces","collapsed":true,"items":[{"text":"LayerExportOptions","link":"/api/textmode.export.js/interfaces/LayerExportOptions.md"},{"text":"JSONRGBAColor","link":"/api/textmode.export.js/interfaces/JSONRGBAColor.md"},{"text":"JSONCellTransform","link":"/api/textmode.export.js/interfaces/JSONCellTransform.md"},{"text":"JSONObjectRowCell","link":"/api/textmode.export.js/interfaces/JSONObjectRowCell.md"},{"text":"JSONObjectRowsCellCollection","link":"/api/textmode.export.js/interfaces/JSONObjectRowsCellCollection.md"},{"text":"JSONLayerGrid","link":"/api/textmode.export.js/interfaces/JSONLayerGrid.md"},{"text":"JSONExportMetadata","link":"/api/textmode.export.js/interfaces/JSONExportMetadata.md"},{"text":"TextmodeSelectedDocumentLayer","link":"/api/textmode.export.js/interfaces/TextmodeSelectedDocumentLayer.md"},{"text":"TextmodeSelectedDocumentJSON","link":"/api/textmode.export.js/interfaces/TextmodeSelectedDocumentJSON.md"},{"text":"TextmodeDocumentLayer","link":"/api/textmode.export.js/interfaces/TextmodeDocumentLayer.md"},{"text":"TextmodeAllDocumentJSON","link":"/api/textmode.export.js/interfaces/TextmodeAllDocumentJSON.md"},{"text":"ExportOverlayPosition","link":"/api/textmode.export.js/interfaces/ExportOverlayPosition.md"},{"text":"ExportOverlayPositionInput","link":"/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md"},{"text":"ExportOverlayController","link":"/api/textmode.export.js/interfaces/ExportOverlayController.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"show","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/show.md"},{"text":"hide","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/hide.md"},{"text":"toggle","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/toggle.md"},{"text":"isVisible","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/isVisible.md"},{"text":"resetPosition","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetPosition.md"},{"text":"getPosition","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/getPosition.md"},{"text":"setPosition","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/setPosition.md"},{"text":"setDefaults","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/setDefaults.md"},{"text":"getDefaults","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/getDefaults.md"},{"text":"resetDefaults","link":"/api/textmode.export.js/interfaces/ExportOverlayController/methods/resetDefaults.md"}]}]},{"text":"TextmodeExportAPI","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"saveCanvas","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveCanvas.md"},{"text":"copyCanvas","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/copyCanvas.md"},{"text":"saveSVG","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveSVG.md"},{"text":"saveStrings","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveStrings.md"},{"text":"toSVG","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toSVG.md"},{"text":"toString","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toString.md"},{"text":"toJSON","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSON.md"},{"text":"toJSONString","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/toJSONString.md"},{"text":"saveJSON","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveJSON.md"},{"text":"saveGIF","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveGIF.md"},{"text":"saveVideo","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI/methods/saveVideo.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"GIFExportProgress","link":"/api/textmode.export.js/type-aliases/GIFExportProgress.md"},{"text":"GIFExportOptions","link":"/api/textmode.export.js/type-aliases/GIFExportOptions.md"},{"text":"ImageExportOptions","link":"/api/textmode.export.js/type-aliases/ImageExportOptions.md"},{"text":"JSONExportTarget","link":"/api/textmode.export.js/type-aliases/JSONExportTarget.md"},{"text":"JSONDocumentFormat","link":"/api/textmode.export.js/type-aliases/JSONDocumentFormat.md"},{"text":"JSONDocumentVersion","link":"/api/textmode.export.js/type-aliases/JSONDocumentVersion.md"},{"text":"JSONExportColorMode","link":"/api/textmode.export.js/type-aliases/JSONExportColorMode.md"},{"text":"JSONColorValue","link":"/api/textmode.export.js/type-aliases/JSONColorValue.md"},{"text":"JSONCellCollection","link":"/api/textmode.export.js/type-aliases/JSONCellCollection.md"},{"text":"TextmodeDocumentJSON","link":"/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md"},{"text":"JSONExportOptions","link":"/api/textmode.export.js/type-aliases/JSONExportOptions.md"},{"text":"SVGExportOptions","link":"/api/textmode.export.js/type-aliases/SVGExportOptions.md"},{"text":"TXTExportOptions","link":"/api/textmode.export.js/type-aliases/TXTExportOptions.md"},{"text":"VideoRecordingState","link":"/api/textmode.export.js/type-aliases/VideoRecordingState.md"},{"text":"VideoExportPhase","link":"/api/textmode.export.js/type-aliases/VideoExportPhase.md"},{"text":"VideoBitratePreset","link":"/api/textmode.export.js/type-aliases/VideoBitratePreset.md"},{"text":"VideoExportFormat","link":"/api/textmode.export.js/type-aliases/VideoExportFormat.md"},{"text":"VideoBitrateMode","link":"/api/textmode.export.js/type-aliases/VideoBitrateMode.md"},{"text":"VideoLatencyMode","link":"/api/textmode.export.js/type-aliases/VideoLatencyMode.md"},{"text":"VideoHardwareAcceleration","link":"/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md"},{"text":"VideoExportErrorCode","link":"/api/textmode.export.js/type-aliases/VideoExportErrorCode.md"},{"text":"VideoExportProgress","link":"/api/textmode.export.js/type-aliases/VideoExportProgress.md"},{"text":"VideoExportOptions","link":"/api/textmode.export.js/type-aliases/VideoExportOptions.md"},{"text":"TXTOverlayDefaults","link":"/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md"},{"text":"JSONOverlayDefaults","link":"/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md"},{"text":"ImageOverlayDefaults","link":"/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md"},{"text":"SVGOverlayDefaults","link":"/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md"},{"text":"GIFOverlayDefaults","link":"/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md"},{"text":"VideoOverlayDefaults","link":"/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md"},{"text":"ExportDefaults","link":"/api/textmode.export.js/type-aliases/ExportDefaults.md"},{"text":"ExportDefaultsPatch","link":"/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"ExportPlugin","link":"/api/textmode.export.js/variables/ExportPlugin.md"}]}] \ No newline at end of file +[{"text":"Animation export","collapsed":true,"items":[{"text":"GIFExportOptions","link":"/api/textmode.export.js/type-aliases/GIFExportOptions.md"},{"text":"GIFExportProgress","link":"/api/textmode.export.js/type-aliases/GIFExportProgress.md"},{"text":"VideoBitrateMode","link":"/api/textmode.export.js/type-aliases/VideoBitrateMode.md"},{"text":"VideoBitratePreset","link":"/api/textmode.export.js/type-aliases/VideoBitratePreset.md"},{"text":"VideoExportFormat","link":"/api/textmode.export.js/type-aliases/VideoExportFormat.md"},{"text":"VideoExportOptions","link":"/api/textmode.export.js/type-aliases/VideoExportOptions.md"},{"text":"VideoExportPhase","link":"/api/textmode.export.js/type-aliases/VideoExportPhase.md"},{"text":"VideoExportProgress","link":"/api/textmode.export.js/type-aliases/VideoExportProgress.md"},{"text":"VideoHardwareAcceleration","link":"/api/textmode.export.js/type-aliases/VideoHardwareAcceleration.md"},{"text":"VideoLatencyMode","link":"/api/textmode.export.js/type-aliases/VideoLatencyMode.md"},{"text":"VideoRecordingState","link":"/api/textmode.export.js/type-aliases/VideoRecordingState.md"}]},{"text":"Canvas capture","collapsed":true,"items":[{"text":"ImageExportOptions","link":"/api/textmode.export.js/type-aliases/ImageExportOptions.md"}]},{"text":"JSON document data","collapsed":true,"items":[{"text":"JSONExportColorMode","link":"/api/textmode.export.js/type-aliases/JSONExportColorMode.md"},{"text":"JSONExportOptions","link":"/api/textmode.export.js/type-aliases/JSONExportOptions.md"},{"text":"JSONExportTarget","link":"/api/textmode.export.js/type-aliases/JSONExportTarget.md"},{"text":"TextmodeDocumentJSON","link":"/api/textmode.export.js/type-aliases/TextmodeDocumentJSON.md"}]},{"text":"Layer data export","collapsed":true,"items":[{"text":"LayerExportOptions","link":"/api/textmode.export.js/interfaces/LayerExportOptions.md"},{"text":"SVGExportOptions","link":"/api/textmode.export.js/type-aliases/SVGExportOptions.md"},{"text":"TXTExportOptions","link":"/api/textmode.export.js/type-aliases/TXTExportOptions.md"}]},{"text":"Overlay","collapsed":true,"items":[{"text":"ExportOverlayController","link":"/api/textmode.export.js/interfaces/ExportOverlayController.md"},{"text":"ExportOverlayPosition","link":"/api/textmode.export.js/interfaces/ExportOverlayPosition.md"},{"text":"ExportOverlayPositionInput","link":"/api/textmode.export.js/interfaces/ExportOverlayPositionInput.md"},{"text":"ExportDefaults","link":"/api/textmode.export.js/type-aliases/ExportDefaults.md"},{"text":"ExportDefaultsPatch","link":"/api/textmode.export.js/type-aliases/ExportDefaultsPatch.md"},{"text":"GIFOverlayDefaults","link":"/api/textmode.export.js/type-aliases/GIFOverlayDefaults.md"},{"text":"ImageOverlayDefaults","link":"/api/textmode.export.js/type-aliases/ImageOverlayDefaults.md"},{"text":"JSONOverlayDefaults","link":"/api/textmode.export.js/type-aliases/JSONOverlayDefaults.md"},{"text":"SVGOverlayDefaults","link":"/api/textmode.export.js/type-aliases/SVGOverlayDefaults.md"},{"text":"TXTOverlayDefaults","link":"/api/textmode.export.js/type-aliases/TXTOverlayDefaults.md"},{"text":"VideoOverlayDefaults","link":"/api/textmode.export.js/type-aliases/VideoOverlayDefaults.md"}]},{"text":"Workflow","collapsed":true,"items":[{"text":"TextmodeExportAPI","link":"/api/textmode.export.js/interfaces/TextmodeExportAPI.md"},{"text":"ExportPlugin","link":"/api/textmode.export.js/variables/ExportPlugin.md"}]}] \ No newline at end of file diff --git a/api/textmode.export.js/variables/ExportPlugin.md b/api/textmode.export.js/variables/ExportPlugin.md index 0c2ce4ef..5b2dbb7c 100644 --- a/api/textmode.export.js/variables/ExportPlugin.md +++ b/api/textmode.export.js/variables/ExportPlugin.md @@ -2,12 +2,12 @@ layout: doc editLink: true title: ExportPlugin -description: Export plugin for textmode.js. +description: Default export plugin instance for the standard textmode.js workflow. category: Variables api: true kind: Variable ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.export.js](../index.md) / ExportPlugin @@ -18,13 +18,5 @@ lastModified: 2026-07-31 const ExportPlugin: TextmodePlugin; ``` -Export plugin for textmode.js. - -Add this plugin to your textmode.js instance to enable exporting artworks -as images, videos, SVG, JSON, and text files. Includes an overlay UI for quick -access to all export options, which can be controlled at runtime. - -## Example - - +Default export plugin instance for the standard textmode.js workflow. diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont.md b/api/textmode.figlet.js/classes/TextmodeFigFont.md index bd24cd79..b1f74d62 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont.md @@ -7,7 +7,7 @@ category: Classes api: true kind: Class ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 hasConstructor: false --- @@ -26,23 +26,23 @@ Parsed FIGfont resource used by `figText()` rendering. | Accessor | Description | | ------ | ------ | -| [name](TextmodeFigFont/accessors/name.md) | The display name associated with this FIGfont. | -| [header](TextmodeFigFont/accessors/header.md) | The parsed FIGfont header metadata. | -| [characters](TextmodeFigFont/accessors/characters.md) | Parsed FIGcharacters keyed by Unicode code point. | -| [hardblank](TextmodeFigFont/accessors/hardblank.md) | Hardblank character declared by the font. | -| [height](TextmodeFigFont/accessors/height.md) | Number of rows in each FIGcharacter. | | [baseline](TextmodeFigFont/accessors/baseline.md) | Baseline row declared by the font. | +| [characters](TextmodeFigFont/accessors/characters.md) | Parsed FIGcharacters keyed by Unicode code point. | | [defaultLayout](TextmodeFigFont/accessors/defaultLayout.md) | Default horizontal layout implied by the header metadata. | | [defaultPrintDirection](TextmodeFigFont/accessors/defaultPrintDirection.md) | Default print direction implied by the FIGfont header metadata. | | [defaultVerticalLayout](TextmodeFigFont/accessors/defaultVerticalLayout.md) | Default vertical layout implied by the FIGfont header metadata. | +| [hardblank](TextmodeFigFont/accessors/hardblank.md) | Hardblank character declared by the font. | +| [header](TextmodeFigFont/accessors/header.md) | The parsed FIGfont header metadata. | +| [height](TextmodeFigFont/accessors/height.md) | Number of rows in each FIGcharacter. | +| [name](TextmodeFigFont/accessors/name.md) | The display name associated with this FIGfont. | ## Methods | Method | Description | | ------ | ------ | +| [\_addOnDispose](TextmodeFigFont/methods/addOnDispose.md) | Register a callback to run when the resource is disposed. | +| [dispose](TextmodeFigFont/methods/dispose.md) | Dispose the resource and invoke all registered callbacks. | | [getCharacter](TextmodeFigFont/methods/getCharacter.md) | Look up a FIGcharacter by Unicode code point or by the first character in a string. | +| [measureText](TextmodeFigFont/methods/measureText.md) | Measure rendered FIGlet text without drawing it. | | [planText](TextmodeFigFont/methods/planText.md) | Plan a string into positioned FIGlet cells and logical lines. | | [renderText](TextmodeFigFont/methods/renderText.md) | Render a string into a FIGlet sub-character grid. | -| [measureText](TextmodeFigFont/methods/measureText.md) | Measure rendered FIGlet text without drawing it. | -| [\_addOnDispose](TextmodeFigFont/methods/addOnDispose.md) | Register a callback to run when the resource is disposed. | -| [dispose](TextmodeFigFont/methods/dispose.md) | Dispose the resource and invoke all registered callbacks. | diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md index 8b98c2b4..e66d330e 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / baseline diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md index 024aaa9d..21a60b28 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / characters diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md index d1cd5f8e..24da017b 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / defaultLayout diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md index a75053ad..7a68fd57 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / defaultPrintDirection diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md index 4b79681d..eba6ff88 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / defaultVerticalLayout diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md index ee39fb56..a4cc71d5 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / hardblank diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md index 88153dec..2585c18d 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / header diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md index 8c705a56..6c2cd66a 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / height diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md index 0a9ea65a..925aabca 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Accessor ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / name diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md index bb26128b..a9cce461 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / \_addOnDispose diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md index f27d00b1..90268326 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / dispose diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md index 3243afec..10ee5b78 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / getCharacter diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md index 8616bc83..6030a0d3 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / measureText diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md index 988a7147..b5d57608 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / planText diff --git a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md index ac35e972..23652dcb 100644 --- a/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md +++ b/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFigFont kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodeFigFont](../../TextmodeFigFont.md) / renderText diff --git a/api/textmode.figlet.js/index.md b/api/textmode.figlet.js/index.md index 631bdc9f..1637c078 100644 --- a/api/textmode.figlet.js/index.md +++ b/api/textmode.figlet.js/index.md @@ -7,41 +7,78 @@ category: API Reference api: true kind: Project ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- # textmode.figlet.js -## Classes +Add FIGlet display typography to a textmode.js sketch. -| Class | Description | -| ------ | ------ | -| [TextmodeFigFont](classes/TextmodeFigFont.md) | Parsed FIGfont resource used by `figText()` rendering. | +Install [FigletPlugin](variables/FigletPlugin.md) to add FIGfont loading, selection, drawing, and +measurement helpers to the sketch's `Textmodifier`. Use +[TextmodeFigFont](classes/TextmodeFigFont.md) when you need to inspect a parsed font, plan its +layout, or render it without drawing to the canvas. -## Interfaces +## Sketch workflow -| Interface | Description | +1. Add [FigletPlugin](variables/FigletPlugin.md) to the sketch's plugins. +2. Load a `.flf` file with [TextmodifierFigletExtensions.loadFigFont](interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md) + or parse raw font data with [TextmodifierFigletExtensions.parseFigFont](interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md). +3. Select the returned font with [TextmodifierFigletExtensions.figFont](interfaces/TextmodifierFigletExtensions/methods/figFont.md). +4. Draw with [TextmodifierFigletExtensions.figText](interfaces/TextmodifierFigletExtensions/methods/figText.md), or measure first + with its width, height, and bounds helpers. + +[FigTextOptions](interfaces/FigTextOptions.md) controls layout, wrapping, direction, and per-cell +colors. Use [TextmodeFigFont](classes/TextmodeFigFont.md) for reusable FIGfont resources and +lower-level planning. + +## FIGfont resources + +Parsed FIGfont resources and metadata for inspecting characters and +font-defined defaults. + +| Name | Description | | ------ | ------ | -| [TextmodifierFigletExtensions](interfaces/TextmodifierFigletExtensions.md) | FIGlet methods added to the `textmode.js` `Textmodifier` API when [FigletPlugin](variables/FigletPlugin.md) is installed. | -| [FigFontHeader](interfaces/FigFontHeader.md) | Parsed FIGfont header metadata from the `.flf` header line. | +| [TextmodeFigFont](classes/TextmodeFigFont.md) | Parsed FIGfont resource used by `figText()` rendering. | | [FigCharacter](interfaces/FigCharacter.md) | A single parsed FIGcharacter from a FIGfont. | -| [FigTextCellContext](interfaces/FigTextCellContext.md) | Public cell metadata exposed to FIGlet styling callbacks. | -| [FigTextOptions](interfaces/FigTextOptions.md) | Layout options for rendering FIGlet text. | +| [FigFontHeader](interfaces/FigFontHeader.md) | Parsed FIGfont header metadata from the `.flf` header line. | + +## Layout and rendering -## Type Aliases +Options and value types that control FIGlet composition, wrapping, +direction, and placement. -| Type Alias | Description | +| Name | Description | | ------ | ------ | +| [FigTextOptions](interfaces/FigTextOptions.md) | Layout options for rendering FIGlet text. | | [FigHorizontalLayout](type-aliases/FigHorizontalLayout.md) | Supported horizontal layout modes for FIGlet rendering. | -| [FigVerticalLayout](type-aliases/FigVerticalLayout.md) | Supported vertical layout modes for multi-line FIGlet rendering. | -| [FigWrapMode](type-aliases/FigWrapMode.md) | Supported wrap modes for FIGlet text layout. | | [FigPrintDirection](type-aliases/FigPrintDirection.md) | Supported print directions for FIGlet text layout. | -| [FigTextColorValue](type-aliases/FigTextColorValue.md) | Accepted color input for per-cell FIGlet styling. | -| [FigTextColorResolver](type-aliases/FigTextColorResolver.md) | Resolver for per-cell FIGlet colors. | | [FigTextAlign](type-aliases/FigTextAlign.md) | Horizontal alignment options for `figText()` placement. | | [FigTextBaseline](type-aliases/FigTextBaseline.md) | Vertical alignment options for `figText()` placement. | +| [FigVerticalLayout](type-aliases/FigVerticalLayout.md) | Supported vertical layout modes for multi-line FIGlet rendering. | +| [FigWrapMode](type-aliases/FigWrapMode.md) | Supported wrap modes for FIGlet text layout. | + +## Styling + +Per-cell color values and callback context for styling rendered FIGlet text. + +| Name | Description | +| ------ | ------ | +| [FigTextCellContext](interfaces/FigTextCellContext.md) | Public cell metadata exposed to FIGlet styling callbacks. | +| [FigTextColorResolver](type-aliases/FigTextColorResolver.md) | Resolver for per-cell FIGlet colors. | +| [FigTextColorValue](type-aliases/FigTextColorValue.md) | Accepted color input for per-cell FIGlet styling. | + +## Textmodifier extensions + +Methods that [FigletPlugin](variables/FigletPlugin.md) adds to a textmode.js sketch. + +| Interface | Description | +| ------ | ------ | +| [TextmodifierFigletExtensions](interfaces/TextmodifierFigletExtensions.md) | FIGlet methods added to the `textmode.js` `Textmodifier` API when [FigletPlugin](variables/FigletPlugin.md) is installed. | + +## Workflow -## Variables +The plugin entrypoint that enables the FIGlet sketch workflow. | Variable | Description | | ------ | ------ | diff --git a/api/textmode.figlet.js/interfaces/FigCharacter.md b/api/textmode.figlet.js/interfaces/FigCharacter.md index 8e4bfbab..42a13bb2 100644 --- a/api/textmode.figlet.js/interfaces/FigCharacter.md +++ b/api/textmode.figlet.js/interfaces/FigCharacter.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.figlet.js/interfaces/FigFontHeader.md b/api/textmode.figlet.js/interfaces/FigFontHeader.md index fcfd305c..17069f12 100644 --- a/api/textmode.figlet.js/interfaces/FigFontHeader.md +++ b/api/textmode.figlet.js/interfaces/FigFontHeader.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -22,13 +22,13 @@ Parsed FIGfont header metadata from the `.flf` header line. | Property | Type | Description | | ------ | ------ | ------ | -| `signature` | `string` | Always `flf2a` for supported FIGfont v2 files. | +| `baseline` | `number` | Baseline row reported by the font. | +| `codetagCount` | `number` | Number of code-tagged characters declared by the font. | +| `commentLines` | `number` | Number of comment lines immediately following the header. | +| `fullLayout` | `number` | Full FIGfont layout flags when present. | | `hardblank` | `string` | Hardblank character used by the font. | | `height` | `number` | Number of rows in every FIGcharacter. | -| `baseline` | `number` | Baseline row reported by the font. | | `maxLength` | `number` | Maximum line length declared by the font. | | `oldLayout` | `number` | Legacy horizontal layout bitfield. | -| `commentLines` | `number` | Number of comment lines immediately following the header. | | `printDirection` | `number` | Font print direction: `0` left-to-right, `1` right-to-left. | -| `fullLayout` | `number` | Full FIGfont layout flags when present. | -| `codetagCount` | `number` | Number of code-tagged characters declared by the font. | +| `signature` | `string` | Always `flf2a` for supported FIGfont v2 files. | diff --git a/api/textmode.figlet.js/interfaces/FigTextCellContext.md b/api/textmode.figlet.js/interfaces/FigTextCellContext.md index aabd64ff..89202771 100644 --- a/api/textmode.figlet.js/interfaces/FigTextCellContext.md +++ b/api/textmode.figlet.js/interfaces/FigTextCellContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -24,10 +24,10 @@ Public cell metadata exposed to FIGlet styling callbacks. | ------ | ------ | ------ | | `char` | `string` | Final drawable sub-character after layout normalization. | | `col` | `number` | Absolute column within the rendered result. | -| `row` | `number` | Absolute row within the rendered result. | -| `inputIndex` | `number` | Zero-based index into the original input string's character sequence. | -| `inputChar` | `string` | Original input character that produced this cell. | | `figCharCode` | `number` | FIGcharacter code used to produce this cell. | -| `subRow` | `number` | Row within the source FIGcharacter. | -| `subCol` | `number` | Column within the source FIGcharacter. | +| `inputChar` | `string` | Original input character that produced this cell. | +| `inputIndex` | `number` | Zero-based index into the original input string's character sequence. | | `lineIndex` | `number` | Logical rendered line index after explicit newline splitting. | +| `row` | `number` | Absolute row within the rendered result. | +| `subCol` | `number` | Column within the source FIGcharacter. | +| `subRow` | `number` | Row within the source FIGcharacter. | diff --git a/api/textmode.figlet.js/interfaces/FigTextOptions.md b/api/textmode.figlet.js/interfaces/FigTextOptions.md index 4702fde2..6bd60259 100644 --- a/api/textmode.figlet.js/interfaces/FigTextOptions.md +++ b/api/textmode.figlet.js/interfaces/FigTextOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -22,10 +22,10 @@ Layout options for rendering FIGlet text. | Property | Type | Description | | ------ | ------ | ------ | +| `cellColor?` | [`FigTextColorResolver`](../type-aliases/FigTextColorResolver.md) | Override or resolve the background color for each rendered FIGlet cell. | +| `charColor?` | [`FigTextColorResolver`](../type-aliases/FigTextColorResolver.md) | Override or resolve the foreground color for each rendered FIGlet cell. | +| `direction?` | [`FigPrintDirection`](../type-aliases/FigPrintDirection.md) | Override the effective print direction for layout. | | `horizontalLayout?` | [`FigHorizontalLayout`](../type-aliases/FigHorizontalLayout.md) | Override the font's default horizontal layout. | +| `maxCols?` | `number` | Maximum rendered columns per logical line before wrapping occurs. | | `verticalLayout?` | [`FigVerticalLayout`](../type-aliases/FigVerticalLayout.md) | Override the vertical composition mode for multi-line FIGlet layout. | -| `direction?` | [`FigPrintDirection`](../type-aliases/FigPrintDirection.md) | Override the effective print direction for layout. | | `wrap?` | [`FigWrapMode`](../type-aliases/FigWrapMode.md) | Optional wrap strategy for multi-line layout. | -| `maxCols?` | `number` | Maximum rendered columns per logical line before wrapping occurs. | -| `charColor?` | [`FigTextColorResolver`](../type-aliases/FigTextColorResolver.md) | Override or resolve the foreground color for each rendered FIGlet cell. | -| `cellColor?` | [`FigTextColorResolver`](../type-aliases/FigTextColorResolver.md) | Override or resolve the background color for each rendered FIGlet cell. | diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md index ad9fdfe3..2c5a5b0c 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -23,12 +23,12 @@ FIGlet methods added to the `textmode.js` `Textmodifier` API when | Method | Description | | ------ | ------ | -| [loadFigFont](TextmodifierFigletExtensions/methods/loadFigFont.md) | Load a FIGlet font from a `.flf` file URL or path. | -| [parseFigFont](TextmodifierFigletExtensions/methods/parseFigFont.md) | Parse a FIGlet font from raw `.flf` contents. | | [figFont](TextmodifierFigletExtensions/methods/figFont.md) | Get the active FIGlet font used by `figText()`. | | [figText](TextmodifierFigletExtensions/methods/figText.md) | Render a FIGlet string onto the current textmode grid using the active FIGlet font. | -| [figTextWidth](TextmodifierFigletExtensions/methods/figTextWidth.md) | Measure the rendered width of a FIGlet string in grid cells. | -| [figTextHeight](TextmodifierFigletExtensions/methods/figTextHeight.md) | Measure the rendered height of a FIGlet string in grid cells. | -| [figTextBounds](TextmodifierFigletExtensions/methods/figTextBounds.md) | Measure the rendered bounds of a FIGlet string in grid cells. | | [figTextAlign](TextmodifierFigletExtensions/methods/figTextAlign.md) | Get the current horizontal FIGlet text alignment. | | [figTextBaseline](TextmodifierFigletExtensions/methods/figTextBaseline.md) | Get the current vertical FIGlet text baseline mode. | +| [figTextBounds](TextmodifierFigletExtensions/methods/figTextBounds.md) | Measure the rendered bounds of a FIGlet string in grid cells. | +| [figTextHeight](TextmodifierFigletExtensions/methods/figTextHeight.md) | Measure the rendered height of a FIGlet string in grid cells. | +| [figTextWidth](TextmodifierFigletExtensions/methods/figTextWidth.md) | Measure the rendered width of a FIGlet string in grid cells. | +| [loadFigFont](TextmodifierFigletExtensions/methods/loadFigFont.md) | Load a FIGlet font from a `.flf` file URL or path. | +| [parseFigFont](TextmodifierFigletExtensions/methods/parseFigFont.md) | Parse a FIGlet font from raw `.flf` contents. | diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md index 37b96c45..37bed7ff 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figFont diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md index edebb677..b890235a 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figText diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md index 3a38f3c1..50fbb925 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figTextAlign diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md index 767ed86f..d5a0803b 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figTextBaseline diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md index 58b5589a..6277af2c 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figTextBounds diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md index 98d93908..35066c51 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figTextHeight diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md index bad16aa1..251b374b 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / figTextWidth diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md index 111728ea..67ec9b16 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / loadFigFont diff --git a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md index 5f1109f0..f5e5002e 100644 --- a/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md +++ b/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md @@ -8,7 +8,7 @@ api: true owner: TextmodifierFigletExtensions kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../../../index.md) / [TextmodifierFigletExtensions](../../TextmodifierFigletExtensions.md) / parseFigFont diff --git a/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md b/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md index 1ae5b505..3acead79 100644 --- a/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md +++ b/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigHorizontalLayout diff --git a/api/textmode.figlet.js/type-aliases/FigPrintDirection.md b/api/textmode.figlet.js/type-aliases/FigPrintDirection.md index 8304724c..54115794 100644 --- a/api/textmode.figlet.js/type-aliases/FigPrintDirection.md +++ b/api/textmode.figlet.js/type-aliases/FigPrintDirection.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigPrintDirection diff --git a/api/textmode.figlet.js/type-aliases/FigTextAlign.md b/api/textmode.figlet.js/type-aliases/FigTextAlign.md index 18d9275c..2a66f8c8 100644 --- a/api/textmode.figlet.js/type-aliases/FigTextAlign.md +++ b/api/textmode.figlet.js/type-aliases/FigTextAlign.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigTextAlign diff --git a/api/textmode.figlet.js/type-aliases/FigTextBaseline.md b/api/textmode.figlet.js/type-aliases/FigTextBaseline.md index 41923bb3..203eca6c 100644 --- a/api/textmode.figlet.js/type-aliases/FigTextBaseline.md +++ b/api/textmode.figlet.js/type-aliases/FigTextBaseline.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigTextBaseline diff --git a/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md b/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md index 651bba7c..b17990da 100644 --- a/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md +++ b/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigTextColorResolver diff --git a/api/textmode.figlet.js/type-aliases/FigTextColorValue.md b/api/textmode.figlet.js/type-aliases/FigTextColorValue.md index d44681e2..53ee2032 100644 --- a/api/textmode.figlet.js/type-aliases/FigTextColorValue.md +++ b/api/textmode.figlet.js/type-aliases/FigTextColorValue.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigTextColorValue diff --git a/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md b/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md index cc0a593e..490e3c06 100644 --- a/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md +++ b/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigVerticalLayout diff --git a/api/textmode.figlet.js/type-aliases/FigWrapMode.md b/api/textmode.figlet.js/type-aliases/FigWrapMode.md index 5019c037..3063da01 100644 --- a/api/textmode.figlet.js/type-aliases/FigWrapMode.md +++ b/api/textmode.figlet.js/type-aliases/FigWrapMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigWrapMode diff --git a/api/textmode.figlet.js/typedoc-sidebar.json b/api/textmode.figlet.js/typedoc-sidebar.json index a072172e..a43e6fa8 100644 --- a/api/textmode.figlet.js/typedoc-sidebar.json +++ b/api/textmode.figlet.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFigFont","link":"/api/textmode.figlet.js/classes/TextmodeFigFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"name","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md"},{"text":"header","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md"},{"text":"characters","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md"},{"text":"hardblank","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md"},{"text":"height","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md"},{"text":"baseline","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md"},{"text":"defaultLayout","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md"},{"text":"defaultPrintDirection","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md"},{"text":"defaultVerticalLayout","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"getCharacter","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md"},{"text":"planText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md"},{"text":"renderText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md"},{"text":"measureText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md"},{"text":"_addOnDispose","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md"},{"text":"dispose","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodifierFigletExtensions","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"loadFigFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md"},{"text":"parseFigFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md"},{"text":"figFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md"},{"text":"figText","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md"},{"text":"figTextWidth","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md"},{"text":"figTextHeight","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md"},{"text":"figTextBounds","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md"},{"text":"figTextAlign","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md"},{"text":"figTextBaseline","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md"}]}]},{"text":"FigFontHeader","link":"/api/textmode.figlet.js/interfaces/FigFontHeader.md"},{"text":"FigCharacter","link":"/api/textmode.figlet.js/interfaces/FigCharacter.md"},{"text":"FigTextCellContext","link":"/api/textmode.figlet.js/interfaces/FigTextCellContext.md"},{"text":"FigTextOptions","link":"/api/textmode.figlet.js/interfaces/FigTextOptions.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"FigHorizontalLayout","link":"/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md"},{"text":"FigVerticalLayout","link":"/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md"},{"text":"FigWrapMode","link":"/api/textmode.figlet.js/type-aliases/FigWrapMode.md"},{"text":"FigPrintDirection","link":"/api/textmode.figlet.js/type-aliases/FigPrintDirection.md"},{"text":"FigTextColorValue","link":"/api/textmode.figlet.js/type-aliases/FigTextColorValue.md"},{"text":"FigTextColorResolver","link":"/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md"},{"text":"FigTextAlign","link":"/api/textmode.figlet.js/type-aliases/FigTextAlign.md"},{"text":"FigTextBaseline","link":"/api/textmode.figlet.js/type-aliases/FigTextBaseline.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"FigletPlugin","link":"/api/textmode.figlet.js/variables/FigletPlugin.md"}]}] \ No newline at end of file +[{"text":"FIGfont resources","collapsed":true,"items":[{"text":"TextmodeFigFont","link":"/api/textmode.figlet.js/classes/TextmodeFigFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"baseline","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/baseline.md"},{"text":"characters","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/characters.md"},{"text":"defaultLayout","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultLayout.md"},{"text":"defaultPrintDirection","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultPrintDirection.md"},{"text":"defaultVerticalLayout","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/defaultVerticalLayout.md"},{"text":"hardblank","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/hardblank.md"},{"text":"header","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/header.md"},{"text":"height","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/height.md"},{"text":"name","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/accessors/name.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"_addOnDispose","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/addOnDispose.md"},{"text":"dispose","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/dispose.md"},{"text":"getCharacter","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/getCharacter.md"},{"text":"measureText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/measureText.md"},{"text":"planText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/planText.md"},{"text":"renderText","link":"/api/textmode.figlet.js/classes/TextmodeFigFont/methods/renderText.md"}]}]},{"text":"FigCharacter","link":"/api/textmode.figlet.js/interfaces/FigCharacter.md"},{"text":"FigFontHeader","link":"/api/textmode.figlet.js/interfaces/FigFontHeader.md"}]},{"text":"Layout and rendering","collapsed":true,"items":[{"text":"FigTextOptions","link":"/api/textmode.figlet.js/interfaces/FigTextOptions.md"},{"text":"FigHorizontalLayout","link":"/api/textmode.figlet.js/type-aliases/FigHorizontalLayout.md"},{"text":"FigPrintDirection","link":"/api/textmode.figlet.js/type-aliases/FigPrintDirection.md"},{"text":"FigTextAlign","link":"/api/textmode.figlet.js/type-aliases/FigTextAlign.md"},{"text":"FigTextBaseline","link":"/api/textmode.figlet.js/type-aliases/FigTextBaseline.md"},{"text":"FigVerticalLayout","link":"/api/textmode.figlet.js/type-aliases/FigVerticalLayout.md"},{"text":"FigWrapMode","link":"/api/textmode.figlet.js/type-aliases/FigWrapMode.md"}]},{"text":"Styling","collapsed":true,"items":[{"text":"FigTextCellContext","link":"/api/textmode.figlet.js/interfaces/FigTextCellContext.md"},{"text":"FigTextColorResolver","link":"/api/textmode.figlet.js/type-aliases/FigTextColorResolver.md"},{"text":"FigTextColorValue","link":"/api/textmode.figlet.js/type-aliases/FigTextColorValue.md"}]},{"text":"Textmodifier extensions","collapsed":true,"items":[{"text":"TextmodifierFigletExtensions","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"figFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md"},{"text":"figText","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md"},{"text":"figTextAlign","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md"},{"text":"figTextBaseline","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md"},{"text":"figTextBounds","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md"},{"text":"figTextHeight","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md"},{"text":"figTextWidth","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md"},{"text":"loadFigFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md"},{"text":"parseFigFont","link":"/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md"}]}]}]},{"text":"Workflow","collapsed":true,"items":[{"text":"FigletPlugin","link":"/api/textmode.figlet.js/variables/FigletPlugin.md"}]}] \ No newline at end of file diff --git a/api/textmode.figlet.js/variables/FigletPlugin.md b/api/textmode.figlet.js/variables/FigletPlugin.md index 42168b45..7561e547 100644 --- a/api/textmode.figlet.js/variables/FigletPlugin.md +++ b/api/textmode.figlet.js/variables/FigletPlugin.md @@ -7,7 +7,7 @@ category: Variables api: true kind: Variable ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.figlet.js](../index.md) / FigletPlugin diff --git a/api/textmode.filters.js/functions/createFiltersPlugin.md b/api/textmode.filters.js/functions/createFiltersPlugin.md deleted file mode 100644 index 739481e3..00000000 --- a/api/textmode.filters.js/functions/createFiltersPlugin.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -layout: doc -editLink: true -deprecated: |- - Use - directly instead. - This function is provided for backwards compatibility only. -title: createFiltersPlugin -description: Creates the textmode.filters.js plugin for textmode.js. -category: Functions -api: true -kind: Function -ecosystem: textmode.js -lastModified: 2026-07-31 ---- - -[textmode.filters.js](../index.md) / createFiltersPlugin - -# Function: createFiltersPlugin() - -```ts -function createFiltersPlugin(): TextmodePlugin; -``` - -Creates the `textmode.filters.js` plugin for textmode.js. - -## Returns - -`TextmodePlugin` - -A textmode.js plugin instance. - -## Example - -```javascript -// Old way (deprecated) -import { createFiltersPlugin } from 'textmode.filters.js'; -const t = textmode.create({ plugins: [createFiltersPlugin()] }); - -// New way (recommended) -import { FiltersPlugin } from 'textmode.filters.js'; -const t = textmode.create({ plugins: [FiltersPlugin] }); -``` - diff --git a/api/textmode.filters.js/index.md b/api/textmode.filters.js/index.md index 7ddd923d..691fe719 100644 --- a/api/textmode.filters.js/index.md +++ b/api/textmode.filters.js/index.md @@ -7,37 +7,26 @@ category: API Reference api: true kind: Project ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- # textmode.filters.js -GPU-accelerated image filters plugin for textmode.js. +Apply GPU-accelerated image filters to finished textmode.js scenes. -This plugin provides customizable visual effects that run entirely on the GPU -via WebGL2 fragment shaders for maximum performance. +Add [FiltersPlugin](variables/FiltersPlugin.md) to a sketch to register the built-in WebGL2 +effects. Use the option interfaces below to configure a filter when adding +it to a layer, the composited scene, or the final presentation stage. -## Available filters +## Choose a filter -### Color adjustment -- [brightness](interfaces/BrightnessOptions.md) - Adjust image brightness -- [contrast](interfaces/ContrastOptions.md) - Adjust image contrast -- [saturation](interfaces/SaturationOptions.md) - Adjust color intensity -- [hueRotate](interfaces/HueRotateOptions.md) - Rotate colors around the color wheel -- [posterize](interfaces/PosterizeOptions.md) - Reduce color levels +**Color adjustment** changes brightness, contrast, saturation, hue, and +posterization. **Distortion** changes pixels, color channels, or grid +geometry. **Stylization** adds glitch, CRT, scanlines, vignette, bloom, and +film grain treatments. -### Distortion -- [chromaticAberration](interfaces/ChromaticAberrationOptions.md) - RGB channel separation -- [pixelate](interfaces/PixelateOptions.md) - Pixelation/mosaic effect -- [gridDistortion](interfaces/GridDistortionOptions.md) - Custom grid warping - -### Stylization -- [glitch](interfaces/GlitchOptions.md) - Digital glitch effect -- [crtMattias](interfaces/CrtMattiasOptions.md) - CRT monitor emulation -- [scanlines](interfaces/ScanlinesOptions.md) - Customizable scanlines -- [vignette](interfaces/VignetteOptions.md) - Darkened edges effect -- [bloom](interfaces/BloomOptions.md) - Glow around bright areas -- [filmGrain](interfaces/FilmGrainOptions.md) - Animated film grain overlay +Start with [FiltersPlugin](variables/FiltersPlugin.md), then read the +[Filters guide](/docs/filters) for scopes and workflows. ## Color adjustment filters @@ -45,32 +34,31 @@ via WebGL2 fragment shaders for maximum performance. | ------ | ------ | | [BrightnessOptions](interfaces/BrightnessOptions.md) | Configuration options for the `'brightness'` filter. | | [ContrastOptions](interfaces/ContrastOptions.md) | Configuration options for the `'contrast'` filter. | -| [SaturationOptions](interfaces/SaturationOptions.md) | Configuration options for the `'saturation'` filter. | | [HueRotateOptions](interfaces/HueRotateOptions.md) | Configuration options for the `'hueRotate'` filter. | | [PosterizeOptions](interfaces/PosterizeOptions.md) | Configuration options for the `'posterize'` filter. | +| [SaturationOptions](interfaces/SaturationOptions.md) | Configuration options for the `'saturation'` filter. | ## Distortion filters | Interface | Description | | ------ | ------ | | [ChromaticAberrationOptions](interfaces/ChromaticAberrationOptions.md) | Configuration options for the `'chromaticAberration'` filter. | -| [PixelateOptions](interfaces/PixelateOptions.md) | Configuration options for the `'pixelate'` filter. | | [GridDistortionOptions](interfaces/GridDistortionOptions.md) | Configuration options for the `'gridDistortion'` filter. | - -## Other - -| Name | Description | -| ------ | ------ | -| [FiltersPlugin](variables/FiltersPlugin.md) | GPU-accelerated image filters plugin for textmode.js. | -| [~~createFiltersPlugin~~](functions/createFiltersPlugin.md) | Creates the `textmode.filters.js` plugin for textmode.js. | +| [PixelateOptions](interfaces/PixelateOptions.md) | Configuration options for the `'pixelate'` filter. | ## Stylization filters | Interface | Description | | ------ | ------ | -| [GlitchOptions](interfaces/GlitchOptions.md) | Configuration options for the `'glitch'` filter. | +| [BloomOptions](interfaces/BloomOptions.md) | Configuration options for the `'bloom'` filter. | | [CrtMattiasOptions](interfaces/CrtMattiasOptions.md) | Configuration options for the `'crtMattias'` filter. | +| [FilmGrainOptions](interfaces/FilmGrainOptions.md) | Configuration options for the `'filmGrain'` filter. | +| [GlitchOptions](interfaces/GlitchOptions.md) | Configuration options for the `'glitch'` filter. | | [ScanlinesOptions](interfaces/ScanlinesOptions.md) | Configuration options for the `'scanlines'` filter. | | [VignetteOptions](interfaces/VignetteOptions.md) | Configuration options for the `'vignette'` filter. | -| [BloomOptions](interfaces/BloomOptions.md) | Configuration options for the `'bloom'` filter. | -| [FilmGrainOptions](interfaces/FilmGrainOptions.md) | Configuration options for the `'filmGrain'` filter. | + +## Workflow + +| Variable | Description | +| ------ | ------ | +| [FiltersPlugin](variables/FiltersPlugin.md) | GPU-accelerated image filters plugin for textmode.js. | diff --git a/api/textmode.filters.js/interfaces/BloomOptions.md b/api/textmode.filters.js/interfaces/BloomOptions.md index d1eb68b3..fe5c4f8b 100644 --- a/api/textmode.filters.js/interfaces/BloomOptions.md +++ b/api/textmode.filters.js/interfaces/BloomOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -29,6 +29,6 @@ Perfect for creating neon, glowing text, or dreamy effects. | Property | Type | Description | | ------ | ------ | ------ | -| `threshold` | `number` | Brightness level above which pixels will glow. - `0.0` = everything glows - `0.5` = mid-brightness and above glows (default) - `1.0` = only the brightest pixels glow **Default** `0.5` | | `intensity` | `number` | Strength of the glow effect. - `0.0` = no visible glow - `1.0` = normal glow intensity (default) - `2.0+` = very bright, intense glow **Default** `1.0` | | `radius` | `number` | Size of the glow spread in pixels. Larger values create a wider, softer glow. - `1.0` = tight glow - `4.0` = moderate spread (default) - `10.0+` = wide, diffuse glow **Default** `4.0` | +| `threshold` | `number` | Brightness level above which pixels will glow. - `0.0` = everything glows - `0.5` = mid-brightness and above glows (default) - `1.0` = only the brightest pixels glow **Default** `0.5` | diff --git a/api/textmode.filters.js/interfaces/BrightnessOptions.md b/api/textmode.filters.js/interfaces/BrightnessOptions.md index 3cd4b105..e35cc398 100644 --- a/api/textmode.filters.js/interfaces/BrightnessOptions.md +++ b/api/textmode.filters.js/interfaces/BrightnessOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md b/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md index 591bdabb..59ed6c1d 100644 --- a/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md +++ b/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/ContrastOptions.md b/api/textmode.filters.js/interfaces/ContrastOptions.md index 7f74f041..27742b5c 100644 --- a/api/textmode.filters.js/interfaces/ContrastOptions.md +++ b/api/textmode.filters.js/interfaces/ContrastOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/CrtMattiasOptions.md b/api/textmode.filters.js/interfaces/CrtMattiasOptions.md index 097ca879..455a692e 100644 --- a/api/textmode.filters.js/interfaces/CrtMattiasOptions.md +++ b/api/textmode.filters.js/interfaces/CrtMattiasOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/FilmGrainOptions.md b/api/textmode.filters.js/interfaces/FilmGrainOptions.md index 03fff95e..e1f0351d 100644 --- a/api/textmode.filters.js/interfaces/FilmGrainOptions.md +++ b/api/textmode.filters.js/interfaces/FilmGrainOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/GlitchOptions.md b/api/textmode.filters.js/interfaces/GlitchOptions.md index e8428923..a1860299 100644 --- a/api/textmode.filters.js/interfaces/GlitchOptions.md +++ b/api/textmode.filters.js/interfaces/GlitchOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/GridDistortionOptions.md b/api/textmode.filters.js/interfaces/GridDistortionOptions.md index 9d86c884..acfcc8bb 100644 --- a/api/textmode.filters.js/interfaces/GridDistortionOptions.md +++ b/api/textmode.filters.js/interfaces/GridDistortionOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -33,9 +33,9 @@ you to create dynamic text distortion effects. | Property | Type | Description | | ------ | ------ | ------ | | `gridCellDimensions` | \[`number`, `number`\] | Grid dimensions as `[columns, rows]`. Should match your textmode grid dimensions. Maximum value: `[128, 128]` **Default** `[80.0, 40.0]` | -| `gridPixelDimensions` | \[`number`, `number`\] | Grid size in pixels as `[width, height]`. Typically calculated as: `[t.grid.cols * t.grid.cellWidth, t.grid.rows * t.grid.cellHeight]` **Default** `[640.0, 320.0]` | | `gridOffsetDimensions` | \[`number`, `number`\] | Grid offset in pixels as `[offsetX, offsetY]`. Use `[t.grid.offsetX, t.grid.offsetY]` to match your grid position. **Default** `[0.0, 0.0]` | -| `widthFactors` | `number`[] | Array of distortion values (0-1) for each column. Must contain at least as many elements as columns (max 128). Values control the relative width of each column: - `0.0` = minimum width - `0.5` = normal width - `1.0` = maximum width **Default** `Array(128).fill(0.5)` | +| `gridPixelDimensions` | \[`number`, `number`\] | Grid size in pixels as `[width, height]`. Typically calculated as: `[t.grid.cols * t.grid.cellWidth, t.grid.rows * t.grid.cellHeight]` **Default** `[640.0, 320.0]` | | `heightFactors` | `number`[] | Array of distortion values (0-1) for each row. Must contain at least as many elements as rows (max 128). Values control the relative height of each row: - `0.0` = minimum height - `0.5` = normal height - `1.0` = maximum height **Default** `Array(128).fill(0.5)` | -| `widthVariationScale` | `number` | Intensity multiplier for width distortion. Higher values create more dramatic width variations. **Default** `0.5` | | `heightVariationScale` | `number` | Intensity multiplier for height distortion. Higher values create more dramatic height variations. **Default** `0.5` | +| `widthFactors` | `number`[] | Array of distortion values (0-1) for each column. Must contain at least as many elements as columns (max 128). Values control the relative width of each column: - `0.0` = minimum width - `0.5` = normal width - `1.0` = maximum width **Default** `Array(128).fill(0.5)` | +| `widthVariationScale` | `number` | Intensity multiplier for width distortion. Higher values create more dramatic width variations. **Default** `0.5` | diff --git a/api/textmode.filters.js/interfaces/HueRotateOptions.md b/api/textmode.filters.js/interfaces/HueRotateOptions.md index 37077973..fd8ace10 100644 --- a/api/textmode.filters.js/interfaces/HueRotateOptions.md +++ b/api/textmode.filters.js/interfaces/HueRotateOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/PixelateOptions.md b/api/textmode.filters.js/interfaces/PixelateOptions.md index b6fa0667..e105d569 100644 --- a/api/textmode.filters.js/interfaces/PixelateOptions.md +++ b/api/textmode.filters.js/interfaces/PixelateOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/PosterizeOptions.md b/api/textmode.filters.js/interfaces/PosterizeOptions.md index f10f7216..d17f7b6e 100644 --- a/api/textmode.filters.js/interfaces/PosterizeOptions.md +++ b/api/textmode.filters.js/interfaces/PosterizeOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/SaturationOptions.md b/api/textmode.filters.js/interfaces/SaturationOptions.md index ef073f22..d609e4cf 100644 --- a/api/textmode.filters.js/interfaces/SaturationOptions.md +++ b/api/textmode.filters.js/interfaces/SaturationOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- diff --git a/api/textmode.filters.js/interfaces/ScanlinesOptions.md b/api/textmode.filters.js/interfaces/ScanlinesOptions.md index 4a0a24d3..a430b869 100644 --- a/api/textmode.filters.js/interfaces/ScanlinesOptions.md +++ b/api/textmode.filters.js/interfaces/ScanlinesOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -30,7 +30,7 @@ the scanlines in crtMattias. | Property | Type | Description | | ------ | ------ | ------ | | `count` | `number` | Number of scanlines across the image height. Higher values create finer, more dense lines. Minimum value: `10.0` **Default** `300.0` | -| `lineWidth` | `number` | Width of the lines relative to the spacing. - `0.0` = very thin lines (mostly transparent) - `0.5` = equal line and gap width - `1.0` = solid (no gaps) **Default** `0.5` | | `intensity` | `number` | Opacity/darkness of the scanlines. - `0.0` = invisible lines - `0.75` = clearly visible (default) - `1.0` = maximum darkness (solid black lines) **Default** `0.75` | +| `lineWidth` | `number` | Width of the lines relative to the spacing. - `0.0` = very thin lines (mostly transparent) - `0.5` = equal line and gap width - `1.0` = solid (no gaps) **Default** `0.5` | | `speed` | `number` | Scrolling speed of the lines. - `0.0` = static lines - `1.0` = normal scrolling speed - Higher values = faster scrolling **Default** `1.0` | | `time` | `number` | Animation time parameter. Increment this value each frame to animate the scrolling effect. **Default** `0.0` | diff --git a/api/textmode.filters.js/interfaces/VignetteOptions.md b/api/textmode.filters.js/interfaces/VignetteOptions.md index 33ce8df4..24f90d85 100644 --- a/api/textmode.filters.js/interfaces/VignetteOptions.md +++ b/api/textmode.filters.js/interfaces/VignetteOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -29,5 +29,5 @@ Useful for creating a cinematic look or highlighting central content. | Property | Type | Description | | ------ | ------ | ------ | | `amount` | `number` | Intensity of the darkening effect. - `0.0` = no vignette - `0.5` = moderate vignette (default) - `1.0` = very dark edges **Default** `0.5` | -| `softness` | `number` | Falloff gradient softness. - `0.0` = hard edge (sharp transition) - `0.5` = moderate gradient (default) - `1.0` = very soft, gradual falloff **Default** `0.5` | | `roundness` | `number` | Shape of the vignette. - `0.0` = rectangular (follows screen edges) - `0.5` = rounded rectangle (default) - `1.0` = circular/elliptical **Default** `0.5` | +| `softness` | `number` | Falloff gradient softness. - `0.0` = hard edge (sharp transition) - `0.5` = moderate gradient (default) - `1.0` = very soft, gradual falloff **Default** `0.5` | diff --git a/api/textmode.filters.js/typedoc-sidebar.json b/api/textmode.filters.js/typedoc-sidebar.json index 5fc3a388..3853da0b 100644 --- a/api/textmode.filters.js/typedoc-sidebar.json +++ b/api/textmode.filters.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Color adjustment filters","collapsed":true,"items":[{"text":"BrightnessOptions","link":"/api/textmode.filters.js/interfaces/BrightnessOptions.md"},{"text":"ContrastOptions","link":"/api/textmode.filters.js/interfaces/ContrastOptions.md"},{"text":"SaturationOptions","link":"/api/textmode.filters.js/interfaces/SaturationOptions.md"},{"text":"HueRotateOptions","link":"/api/textmode.filters.js/interfaces/HueRotateOptions.md"},{"text":"PosterizeOptions","link":"/api/textmode.filters.js/interfaces/PosterizeOptions.md"}]},{"text":"Distortion filters","collapsed":true,"items":[{"text":"ChromaticAberrationOptions","link":"/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md"},{"text":"PixelateOptions","link":"/api/textmode.filters.js/interfaces/PixelateOptions.md"},{"text":"GridDistortionOptions","link":"/api/textmode.filters.js/interfaces/GridDistortionOptions.md"}]},{"text":"Other","collapsed":true,"items":[{"text":"FiltersPlugin","link":"/api/textmode.filters.js/variables/FiltersPlugin.md"},{"text":"createFiltersPlugin","link":"/api/textmode.filters.js/functions/createFiltersPlugin.md"}]},{"text":"Stylization filters","collapsed":true,"items":[{"text":"GlitchOptions","link":"/api/textmode.filters.js/interfaces/GlitchOptions.md"},{"text":"CrtMattiasOptions","link":"/api/textmode.filters.js/interfaces/CrtMattiasOptions.md"},{"text":"ScanlinesOptions","link":"/api/textmode.filters.js/interfaces/ScanlinesOptions.md"},{"text":"VignetteOptions","link":"/api/textmode.filters.js/interfaces/VignetteOptions.md"},{"text":"BloomOptions","link":"/api/textmode.filters.js/interfaces/BloomOptions.md"},{"text":"FilmGrainOptions","link":"/api/textmode.filters.js/interfaces/FilmGrainOptions.md"}]}] \ No newline at end of file +[{"text":"Color adjustment filters","collapsed":true,"items":[{"text":"BrightnessOptions","link":"/api/textmode.filters.js/interfaces/BrightnessOptions.md"},{"text":"ContrastOptions","link":"/api/textmode.filters.js/interfaces/ContrastOptions.md"},{"text":"HueRotateOptions","link":"/api/textmode.filters.js/interfaces/HueRotateOptions.md"},{"text":"PosterizeOptions","link":"/api/textmode.filters.js/interfaces/PosterizeOptions.md"},{"text":"SaturationOptions","link":"/api/textmode.filters.js/interfaces/SaturationOptions.md"}]},{"text":"Distortion filters","collapsed":true,"items":[{"text":"ChromaticAberrationOptions","link":"/api/textmode.filters.js/interfaces/ChromaticAberrationOptions.md"},{"text":"GridDistortionOptions","link":"/api/textmode.filters.js/interfaces/GridDistortionOptions.md"},{"text":"PixelateOptions","link":"/api/textmode.filters.js/interfaces/PixelateOptions.md"}]},{"text":"Stylization filters","collapsed":true,"items":[{"text":"BloomOptions","link":"/api/textmode.filters.js/interfaces/BloomOptions.md"},{"text":"CrtMattiasOptions","link":"/api/textmode.filters.js/interfaces/CrtMattiasOptions.md"},{"text":"FilmGrainOptions","link":"/api/textmode.filters.js/interfaces/FilmGrainOptions.md"},{"text":"GlitchOptions","link":"/api/textmode.filters.js/interfaces/GlitchOptions.md"},{"text":"ScanlinesOptions","link":"/api/textmode.filters.js/interfaces/ScanlinesOptions.md"},{"text":"VignetteOptions","link":"/api/textmode.filters.js/interfaces/VignetteOptions.md"}]},{"text":"Workflow","collapsed":true,"items":[{"text":"FiltersPlugin","link":"/api/textmode.filters.js/variables/FiltersPlugin.md"}]}] \ No newline at end of file diff --git a/api/textmode.filters.js/variables/FiltersPlugin.md b/api/textmode.filters.js/variables/FiltersPlugin.md index 35e14a4d..dfb1e374 100644 --- a/api/textmode.filters.js/variables/FiltersPlugin.md +++ b/api/textmode.filters.js/variables/FiltersPlugin.md @@ -7,7 +7,7 @@ category: Variables api: true kind: Variable ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.filters.js](../index.md) / FiltersPlugin diff --git a/api/textmode.js/classes/TextmodeCamera.md b/api/textmode.js/classes/TextmodeCamera.md index 23c64e99..ffa0095a 100644 --- a/api/textmode.js/classes/TextmodeCamera.md +++ b/api/textmode.js/classes/TextmodeCamera.md @@ -6,7 +6,7 @@ description: Mutable camera object used for p5-style camera workflows. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md index 1870f061..5bab04bc 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / eyeX diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md index 05b11a63..3d45dcbf 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / eyeY diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md index a652c74f..b9083760 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / eyeZ diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md index 9205ed4c..bb5681d9 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / targetX diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md index 919e810d..1a674cf8 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / targetY diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md index 3e3b3f58..c83a2f23 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / targetZ diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md index 5ca77ba8..c31a17e4 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upX.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upX.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / upX diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md index 4908ca6a..8deb1836 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upY.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upY.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / upY diff --git a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md index 6f6b60a7..c3cadc70 100644 --- a/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md +++ b/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeCamera kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / upZ diff --git a/api/textmode.js/classes/TextmodeCamera/methods/copy.md b/api/textmode.js/classes/TextmodeCamera/methods/copy.md index 8872aa4b..0dd0a930 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/copy.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/copy.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeCamera kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / copy diff --git a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md index d159e860..e1b67c81 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeCamera kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / lookAt @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts lookAt( - x, - y, + x, + y, z): this; ``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/move.md b/api/textmode.js/classes/TextmodeCamera/methods/move.md index 0373ea6e..f2c8300d 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/move.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/move.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeCamera kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / move @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts move( - dx, - dy, + dx, + dy, dz): this; ``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md index c23f2a87..d258af8f 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeCamera kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / setPosition @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts setPosition( - x, - y, + x, + y, z): this; ``` diff --git a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md index 21b30cf5..240206b0 100644 --- a/api/textmode.js/classes/TextmodeCamera/methods/setUp.md +++ b/api/textmode.js/classes/TextmodeCamera/methods/setUp.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeCamera kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeCamera](../../TextmodeCamera.md) / setUp @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts setUp( - x, - y, + x, + y, z): this; ``` diff --git a/api/textmode.js/classes/TextmodeFramebuffer.md b/api/textmode.js/classes/TextmodeFramebuffer.md index d77ba896..a6400aae 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer.md +++ b/api/textmode.js/classes/TextmodeFramebuffer.md @@ -6,7 +6,7 @@ description: Framebuffer class for managing offscreen rendering targets initiali category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md index a3fb7a8e..14fef793 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeFramebuffer kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / attachmentCount diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md index a6c2f570..82ec3761 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeFramebuffer kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / framebuffer diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md index 99a91740..c0e1d024 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeFramebuffer kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / height diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md index 672f284e..e51a4b54 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeFramebuffer kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / textures diff --git a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md index d4ae9dca..e25ce1a5 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeFramebuffer kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / width diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md index 216a1f0c..181e78b6 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeFramebuffer kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / begin diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md index 63b88c74..15b2e4ea 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeFramebuffer kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / dispose diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md index 9e3f8cd9..45a4ff1b 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeFramebuffer kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / end diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md index f92bd23a..c9f9d6ab 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeFramebuffer kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / readPixels diff --git a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md index af0fb701..ffe8bb87 100644 --- a/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md +++ b/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeFramebuffer kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeFramebuffer](../../TextmodeFramebuffer.md) / resize diff --git a/api/textmode.js/classes/TextmodeGlyphRamp.md b/api/textmode.js/classes/TextmodeGlyphRamp.md index cd980c3b..0003e1d7 100644 --- a/api/textmode.js/classes/TextmodeGlyphRamp.md +++ b/api/textmode.js/classes/TextmodeGlyphRamp.md @@ -6,7 +6,7 @@ description: Immutable character sequence for mapping numbers to glyphs. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: true --- @@ -108,8 +108,8 @@ Character from this ramp. ```ts at( - value, - min, + value, + min, max): string; ``` diff --git a/api/textmode.js/classes/TextmodeGrid.md b/api/textmode.js/classes/TextmodeGrid.md index 949906d7..0e9f69ff 100644 --- a/api/textmode.js/classes/TextmodeGrid.md +++ b/api/textmode.js/classes/TextmodeGrid.md @@ -6,7 +6,7 @@ description: Grid used by a textmode layer. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md index 02007593..cc052683 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / cellHeight diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md index b9f7e64b..8808dd37 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / cellWidth diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md index bdf9e22f..cb6dcb46 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/cols.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/cols.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / cols diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/height.md b/api/textmode.js/classes/TextmodeGrid/accessors/height.md index 79792e1d..9bc09b3e 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/height.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/height.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / height diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md index 0ee303d7..00b35d4a 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / offsetX diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md index b5d8115d..8bbdee4b 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / offsetY diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md index df335515..d60b651f 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/rows.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/rows.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / rows diff --git a/api/textmode.js/classes/TextmodeGrid/accessors/width.md b/api/textmode.js/classes/TextmodeGrid/accessors/width.md index 55320abf..43e8113a 100644 --- a/api/textmode.js/classes/TextmodeGrid/accessors/width.md +++ b/api/textmode.js/classes/TextmodeGrid/accessors/width.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: TextmodeGrid kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / width diff --git a/api/textmode.js/classes/TextmodeGrid/methods/reset.md b/api/textmode.js/classes/TextmodeGrid/methods/reset.md index 669521dc..c8efb63c 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/reset.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/reset.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeGrid kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / reset diff --git a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md index b79a3e39..29be7868 100644 --- a/api/textmode.js/classes/TextmodeGrid/methods/responsive.md +++ b/api/textmode.js/classes/TextmodeGrid/methods/responsive.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeGrid kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeGrid](../../TextmodeGrid.md) / responsive diff --git a/api/textmode.js/classes/TextmodeRandom.md b/api/textmode.js/classes/TextmodeRandom.md index fc643849..2914f42e 100644 --- a/api/textmode.js/classes/TextmodeRandom.md +++ b/api/textmode.js/classes/TextmodeRandom.md @@ -6,7 +6,7 @@ description: A deterministic pseudo-random number generator for textmode sketche category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: true --- diff --git a/api/textmode.js/classes/TextmodeShader.md b/api/textmode.js/classes/TextmodeShader.md index 62a24fd8..5efdbb78 100644 --- a/api/textmode.js/classes/TextmodeShader.md +++ b/api/textmode.js/classes/TextmodeShader.md @@ -2,11 +2,11 @@ layout: doc editLink: true title: TextmodeShader -description: WebGL shader program created by Textmodifier.createMaterialShader, Textmodifier.createFilterShader, or Textmodifier.createShader. +description: WebGL shader program created by Textmodifier.createMaterialShader or Textmodifier.createShader. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -14,8 +14,7 @@ hasConstructor: false # Class: TextmodeShader -WebGL shader program created by [Textmodifier.createMaterialShader](Textmodifier/methods/createMaterialShader.md), -[Textmodifier.createFilterShader](Textmodifier/methods/createFilterShader.md), or [Textmodifier.createShader](Textmodifier/methods/createShader.md). +WebGL shader program created by [Textmodifier.createMaterialShader](Textmodifier/methods/createMaterialShader.md) or [Textmodifier.createShader](Textmodifier/methods/createShader.md). Use shaders and set uniforms via [Textmodifier.shader](Textmodifier/methods/shader.md), [Textmodifier.setUniform](Textmodifier/methods/setUniform.md), and [Textmodifier.setUniforms](Textmodifier/methods/setUniforms.md). diff --git a/api/textmode.js/classes/TextmodeVector.md b/api/textmode.js/classes/TextmodeVector.md index b4e3fedb..a27a3e93 100644 --- a/api/textmode.js/classes/TextmodeVector.md +++ b/api/textmode.js/classes/TextmodeVector.md @@ -6,7 +6,7 @@ description: Mutable two- or three-dimensional vector for creative-coding math. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: true --- @@ -31,8 +31,8 @@ Use [Textmodifier.createVector](Textmodifier/methods/createVector.md) to create ```ts new TextmodeVector( - x?, - y?, + x?, + y?, z?): TextmodeVector; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/add.md b/api/textmode.js/classes/TextmodeVector/methods/add.md index a5ff479a..c0f22be0 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/add.md +++ b/api/textmode.js/classes/TextmodeVector/methods/add.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / add @@ -44,8 +44,8 @@ This vector. ```ts add( - x?, - y?, + x?, + y?, z?): this; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/copy.md b/api/textmode.js/classes/TextmodeVector/methods/copy.md index c201a51c..81cc1845 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/copy.md +++ b/api/textmode.js/classes/TextmodeVector/methods/copy.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / copy diff --git a/api/textmode.js/classes/TextmodeVector/methods/cross.md b/api/textmode.js/classes/TextmodeVector/methods/cross.md index 5571f8f2..a01cb3df 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/cross.md +++ b/api/textmode.js/classes/TextmodeVector/methods/cross.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / cross @@ -42,8 +42,8 @@ A new vector containing the cross product. ```ts cross( - x?, - y?, + x?, + y?, z?): TextmodeVector; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/dist.md b/api/textmode.js/classes/TextmodeVector/methods/dist.md index cda731eb..04969dce 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dist.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dist.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / dist @@ -42,8 +42,8 @@ Euclidean distance between the two points. ```ts dist( - x?, - y?, + x?, + y?, z?): number; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/div.md b/api/textmode.js/classes/TextmodeVector/methods/div.md index f70a0188..6d0081c0 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/div.md +++ b/api/textmode.js/classes/TextmodeVector/methods/div.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / div @@ -68,8 +68,8 @@ This vector. ```ts div( - x, - y, + x, + y, z?): this; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/dot.md b/api/textmode.js/classes/TextmodeVector/methods/dot.md index 199ae927..8d28e0db 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/dot.md +++ b/api/textmode.js/classes/TextmodeVector/methods/dot.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / dot @@ -42,8 +42,8 @@ Dot product. ```ts dot( - x?, - y?, + x?, + y?, z?): number; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/heading.md b/api/textmode.js/classes/TextmodeVector/methods/heading.md index bd43c21a..fc4547a2 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/heading.md +++ b/api/textmode.js/classes/TextmodeVector/methods/heading.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / heading diff --git a/api/textmode.js/classes/TextmodeVector/methods/limit.md b/api/textmode.js/classes/TextmodeVector/methods/limit.md index 4c3acbec..362a446d 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/limit.md +++ b/api/textmode.js/classes/TextmodeVector/methods/limit.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / limit diff --git a/api/textmode.js/classes/TextmodeVector/methods/mag.md b/api/textmode.js/classes/TextmodeVector/methods/mag.md index 625ece54..de16b03c 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mag.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / mag diff --git a/api/textmode.js/classes/TextmodeVector/methods/magSq.md b/api/textmode.js/classes/TextmodeVector/methods/magSq.md index 05b3c0f9..05ac6e5b 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/magSq.md +++ b/api/textmode.js/classes/TextmodeVector/methods/magSq.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / magSq diff --git a/api/textmode.js/classes/TextmodeVector/methods/mult.md b/api/textmode.js/classes/TextmodeVector/methods/mult.md index 1fb83d89..83b1c8b8 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/mult.md +++ b/api/textmode.js/classes/TextmodeVector/methods/mult.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / mult @@ -68,8 +68,8 @@ This vector. ```ts mult( - x, - y, + x, + y, z?): this; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/normalize.md b/api/textmode.js/classes/TextmodeVector/methods/normalize.md index 8142a039..37a087c3 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/normalize.md +++ b/api/textmode.js/classes/TextmodeVector/methods/normalize.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / normalize diff --git a/api/textmode.js/classes/TextmodeVector/methods/set.md b/api/textmode.js/classes/TextmodeVector/methods/set.md index 3cad3dfa..382e298e 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/set.md +++ b/api/textmode.js/classes/TextmodeVector/methods/set.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / set @@ -45,8 +45,8 @@ This vector. ```ts set( - x?, - y?, + x?, + y?, z?): this; ``` diff --git a/api/textmode.js/classes/TextmodeVector/methods/setMag.md b/api/textmode.js/classes/TextmodeVector/methods/setMag.md index da7e3ff5..302ab071 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/setMag.md +++ b/api/textmode.js/classes/TextmodeVector/methods/setMag.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / setMag diff --git a/api/textmode.js/classes/TextmodeVector/methods/sub.md b/api/textmode.js/classes/TextmodeVector/methods/sub.md index 46849413..50c9b678 100644 --- a/api/textmode.js/classes/TextmodeVector/methods/sub.md +++ b/api/textmode.js/classes/TextmodeVector/methods/sub.md @@ -7,7 +7,7 @@ category: Methods api: true owner: TextmodeVector kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [TextmodeVector](../../TextmodeVector.md) / sub @@ -44,8 +44,8 @@ This vector. ```ts sub( - x?, - y?, + x?, + y?, z?): this; ``` diff --git a/api/textmode.js/classes/Textmodifier.md b/api/textmode.js/classes/Textmodifier.md index 14454b7d..e70633a3 100644 --- a/api/textmode.js/classes/Textmodifier.md +++ b/api/textmode.js/classes/Textmodifier.md @@ -6,7 +6,7 @@ description: The main textmode.js drawing context. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -22,9 +22,191 @@ one; when a canvas is supplied, it renders into or over that element depending on the chosen options. -## Properties +## 2D drawing -| Property | Description | +Draw points, lines, curves, and planar primitives. + +| Method | Description | +| ------ | ------ | +| [arc](Textmodifier/methods/arc.md) | Draw an arc with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | +| [bezierCurve](Textmodifier/methods/bezierCurve.md) | Draw a smooth cubic Bezier curve between two points. The curve thickness is controlled by the current [lineWeight](Textmodifier/methods/lineWeight.md) setting. | +| [ellipse](Textmodifier/methods/ellipse.md) | Draw an ellipse with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | +| [line](Textmodifier/methods/line.md) | Draw a line from `(x1, y1)` to `(x2, y2)`. | +| [lineWeight](Textmodifier/methods/lineWeight.md) | Set or get line thickness for subsequent line and curve drawing. | +| [point](Textmodifier/methods/point.md) | Draw one cell with the current settings. | +| [rect](Textmodifier/methods/rect.md) | Draw a rectangle with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | +| [triangle](Textmodifier/methods/triangle.md) | Draw a triangle with the current settings. | + +## 3D drawing + +Draw built-in three-dimensional primitives. + +| Method | Description | +| ------ | ------ | +| [box](Textmodifier/methods/box.md) | Draw a box mesh primitive. | +| [cone](Textmodifier/methods/cone.md) | Draw a cone mesh primitive. | +| [cylinder](Textmodifier/methods/cylinder.md) | Draw a cylinder mesh primitive. | +| [ellipsoid](Textmodifier/methods/ellipsoid.md) | Draw an ellipsoid mesh primitive. | +| [sphere](Textmodifier/methods/sphere.md) | Draw a sphere mesh primitive. | +| [torus](Textmodifier/methods/torus.md) | Draw a torus mesh primitive. | + +## Animation & timing + +Control rendering cadence and read elapsed sketch time. + +| Name | Description | +| ------ | ------ | +| [frameCount](Textmodifier/accessors/frameCount.md) | Current frame count. | +| [millis](Textmodifier/accessors/millis.md) | Milliseconds since the sketch started running. | +| [secs](Textmodifier/accessors/secs.md) | Seconds since the sketch started running. | +| [deltaTime](Textmodifier/methods/deltaTime.md) | Time in milliseconds between the current frame and the previous frame. | +| [frameRate](Textmodifier/methods/frameRate.md) | Set the target frame rate, or get the current measured frame rate when called without arguments. | +| [isLooping](Textmodifier/methods/isLooping.md) | Whether the automatic render loop is currently running. | +| [loop](Textmodifier/methods/loop.md) | Resume the rendering loop if it was stopped by [noLoop](Textmodifier/methods/noLoop.md). | +| [noLoop](Textmodifier/methods/noLoop.md) | Stop the automatic rendering loop. | +| [redraw](Textmodifier/methods/redraw.md) | Render a fixed number of frames on demand. | +| [targetFrameRate](Textmodifier/methods/targetFrameRate.md) | Set or get the target frame rate limit. | + +## Cameras & projection + +Control the camera and projection used for spatial drawing. + +| Method | Description | +| ------ | ------ | +| [camera](Textmodifier/methods/camera.md) | Set an explicit camera transform for subsequent draw calls. | +| [createCamera](Textmodifier/methods/createCamera.md) | Create and activate a camera initialized from the current render camera state. | +| [lookAt](Textmodifier/methods/lookAt.md) | Update the look-at target and optional up vector for the active camera. | +| [ortho](Textmodifier/methods/ortho.md) | Enable orthographic projection for subsequent shape drawing. | +| [perspective](Textmodifier/methods/perspective.md) | Enable perspective projection and optionally set projection parameters. | +| [resetCamera](Textmodifier/methods/resetCamera.md) | Reset to the default auto camera behavior. | +| [setCamera](Textmodifier/methods/setCamera.md) | Activate a previously created camera object. | + +## Canvas & display + +Inspect and resize the canvas, display, and overlay output. + +| Name | Description | +| ------ | ------ | +| [displayHeight](Textmodifier/properties/displayHeight.md) | Physical screen height in pixels. | +| [displayWidth](Textmodifier/properties/displayWidth.md) | Physical screen width in pixels. | +| [windowHeight](Textmodifier/properties/windowHeight.md) | Current browser window height in pixels. | +| [windowWidth](Textmodifier/properties/windowWidth.md) | Current browser window width in pixels. | +| [canvas](Textmodifier/accessors/canvas.md) | Canvas containing the rendered output. | +| [height](Textmodifier/accessors/height.md) | Canvas height in pixels. | +| [overlay](Textmodifier/accessors/overlay.md) | Overlay source image for the target canvas or video, when overlay mode is enabled. | +| [width](Textmodifier/accessors/width.md) | Canvas width in pixels. | +| [pixelDensity](Textmodifier/methods/pixelDensity.md) | Get the current pixel density for HiDPI rendering. | +| [resizeCanvas](Textmodifier/methods/resizeCanvas.md) | Resize the canvas and adjust all related components accordingly. | +| [windowResized](Textmodifier/methods/windowResized.md) | Set the callback that runs after a window resize. | + +## Characters & color + +Set the glyph, colors, and per-character appearance for later drawing. + +| Method | Description | +| ------ | ------ | +| [background](Textmodifier/methods/background.md) | Current background color. | +| [cellColor](Textmodifier/methods/cellColor.md) | Current cell background color. | +| [char](Textmodifier/methods/char.md) | Current character string used for drawing. | +| [charColor](Textmodifier/methods/charColor.md) | Current character color. | +| [charRotation](Textmodifier/methods/charRotation.md) | Set the character rotation for subsequent drawing, or get the current angle. | +| [clear](Textmodifier/methods/clear.md) | Clear the layer currently drawing to. | +| [color](Textmodifier/methods/color.md) | Create a reusable color object from a grayscale value. | +| [colorMode](Textmodifier/methods/colorMode.md) | Current color interpretation mode. | +| [fill](Textmodifier/methods/fill.md) | Alias for [cellColor](Textmodifier/methods/cellColor.md). Current fill (cell background) color. | +| [flipX](Textmodifier/methods/flipX.md) | Toggle horizontal flipping for subsequent characters, or get the current state. | +| [flipY](Textmodifier/methods/flipY.md) | Toggle vertical flipping for subsequent characters, or get the current state. | +| [invert](Textmodifier/methods/invert.md) | Toggle character/cell color inversion, or get the current state. | +| [stroke](Textmodifier/methods/stroke.md) | Alias for [charColor](Textmodifier/methods/charColor.md). Current stroke (character) color. | + +## Conversion & filters + +Convert source imagery and post-process rendered output. + +| Name | Description | +| ------ | ------ | +| [conversions](Textmodifier/accessors/conversions.md) | Access the conversion manager for this Textmodifier instance. | +| [filters](Textmodifier/accessors/filters.md) | Filter manager for this Textmodifier instance. | +| [filter](Textmodifier/methods/filter.md) | Apply a filter to the final composited output. | + +## Custom geometry + +Assemble vertex-based shapes with explicit topology. + +| Name | Description | +| ------ | ------ | +| [LINE\_LOOP](Textmodifier/properties/LINE_LOOP.md) | Draw consecutive vertices as one connected closed loop. | +| [LINE\_STRIP](Textmodifier/properties/LINE_STRIP.md) | Draw consecutive vertices as one connected open path. | +| [LINES](Textmodifier/properties/LINES.md) | Draw each pair of recorded vertices as an independent line segment. | +| [POINTS](Textmodifier/properties/POINTS.md) | Draw each recorded vertex as a separate point. | +| [QUAD\_STRIP](Textmodifier/properties/QUAD_STRIP.md) | Draw paired vertices as a connected strip of quads. | +| [QUADS](Textmodifier/properties/QUADS.md) | Draw each group of four vertices as a quad split into two triangles. | +| [TRIANGLE\_FAN](Textmodifier/properties/TRIANGLE_FAN.md) | Draw triangles that all share the first recorded vertex. | +| [TRIANGLE\_STRIP](Textmodifier/properties/TRIANGLE_STRIP.md) | Draw overlapping triplets of vertices as a connected triangle strip. | +| [TRIANGLES](Textmodifier/properties/TRIANGLES.md) | Draw each group of three vertices as an independent triangle. | +| [beginShape](Textmodifier/methods/beginShape.md) | Start recording vertices for a custom 2D or 3D shape. Call [vertex](Textmodifier/methods/vertex.md) one or more times, then call [endShape](Textmodifier/methods/endShape.md) to draw the recorded shape. | +| [endShape](Textmodifier/methods/endShape.md) | Finish the active custom shape and enqueue its geometry. | +| [vertex](Textmodifier/methods/vertex.md) | Add a vertex to the active custom shape. The current transform, character, color, and line state are captured for this vertex. | + +## Gamepad input + +Read connected controllers and react to gamepad events. + +| Name | Description | +| ------ | ------ | +| [gamepads](Textmodifier/properties/gamepads.md) | Currently connected gamepads as a compact readonly list. | +| [gamepad](Textmodifier/methods/gamepad.md) | Resolve a connected gamepad by its browser-assigned slot index. | +| [gamepadAxisChanged](Textmodifier/methods/gamepadAxisChanged.md) | Register the single-callback handler for meaningful gamepad axis changes. | +| [gamepadButtonPressed](Textmodifier/methods/gamepadButtonPressed.md) | Register the single-callback handler for gamepad button press events. | +| [gamepadButtonReleased](Textmodifier/methods/gamepadButtonReleased.md) | Register the single-callback handler for gamepad button release events. | +| [gamepadConnected](Textmodifier/methods/gamepadConnected.md) | Register the single-callback handler for gamepad connection events. | +| [gamepadDisconnected](Textmodifier/methods/gamepadDisconnected.md) | Register the single-callback handler for gamepad disconnection events. | + +## Grid, fonts & glyphs + +Configure the drawing grid and the glyph source that populates it. + +| Name | Description | +| ------ | ------ | +| [font](Textmodifier/accessors/font.md) | Font or tileset used by the current drawing layer. | +| [grid](Textmodifier/accessors/grid.md) | Grid for the layer currently being drawn. | +| [createGlyphRamp](Textmodifier/methods/createGlyphRamp.md) | Create a reusable glyph ramp from a character sequence. | +| [fontSize](Textmodifier/methods/fontSize.md) | Set or get the base layer font size. | +| [loadFont](Textmodifier/methods/loadFont.md) | Load a font and optionally set it as the base layer's active font. | +| [loadTileset](Textmodifier/methods/loadTileset.md) | Load a tileset and optionally set it as the base layer's active glyph source. | +| [useTileColors](Textmodifier/methods/useTileColors.md) | Configure authored tileset color preservation on the base layer. | + +## Input events + +Subscribe to input through the shared event interface. + +| Method | Description | +| ------ | ------ | +| [inputGrid](Textmodifier/methods/inputGrid.md) | Get or set the grid used for mouse and touch coordinate mapping. | +| [off](Textmodifier/methods/off.md) | Remove a previously registered input event listener. | +| [on](Textmodifier/methods/on.md) | Register an input event listener. | +| [once](Textmodifier/methods/once.md) | Register an input event listener that removes itself after the first invocation. | + +## Keyboard input + +Read keyboard state and react to keyboard events. + +| Name | Description | +| ------ | ------ | +| [lastKeyPressed](Textmodifier/properties/lastKeyPressed.md) | Last key pressed, or `null` before any key press. | +| [lastKeyReleased](Textmodifier/properties/lastKeyReleased.md) | Last key released, or `null` before any key release. | +| [modifierState](Textmodifier/properties/modifierState.md) | Current modifier key state. | +| [pressedKeys](Textmodifier/properties/pressedKeys.md) | Keys currently being held down. | +| [isKeyPressed](Textmodifier/methods/isKeyPressed.md) | Check whether a key is currently pressed. | +| [keyPressed](Textmodifier/methods/keyPressed.md) | Register the single-callback handler for key press events. | +| [keyReleased](Textmodifier/methods/keyReleased.md) | Register the single-callback handler for key release events. | +| [keyTyped](Textmodifier/methods/keyTyped.md) | Register the single-callback handler for printable character input. | + +## Layers & compositing + +Manage layer stacks and choose how their output combines. + +| Name | Description | | ------ | ------ | | [BLEND\_ADDITIVE](Textmodifier/properties/BLEND_ADDITIVE.md) | Add the layer's color channels to the layers below it. | | [BLEND\_COLOR\_BURN](Textmodifier/properties/BLEND_COLOR_BURN.md) | Darken the layers below by inverting the color dodge relationship. | @@ -40,214 +222,184 @@ on the chosen options. | [BLEND\_SCREEN](Textmodifier/properties/BLEND_SCREEN.md) | Screen the layer against the layers below it. | | [BLEND\_SOFT\_LIGHT](Textmodifier/properties/BLEND_SOFT_LIGHT.md) | Apply a softer contrast blend based on the layer's brightness. | | [BLEND\_SUBTRACT](Textmodifier/properties/BLEND_SUBTRACT.md) | Subtract the layer's colors from the layers below it. | -| [displayHeight](Textmodifier/properties/displayHeight.md) | Physical screen height in pixels. | -| [displayWidth](Textmodifier/properties/displayWidth.md) | Physical screen width in pixels. | -| [gamepads](Textmodifier/properties/gamepads.md) | Currently connected gamepads as a compact readonly list. | -| [lastKeyPressed](Textmodifier/properties/lastKeyPressed.md) | Last key pressed, or `null` before any key press. | -| [lastKeyReleased](Textmodifier/properties/lastKeyReleased.md) | Last key released, or `null` before any key release. | -| [LINE\_LOOP](Textmodifier/properties/LINE_LOOP.md) | Draw consecutive vertices as one connected closed loop. | -| [LINE\_STRIP](Textmodifier/properties/LINE_STRIP.md) | Draw consecutive vertices as one connected open path. | -| [LINES](Textmodifier/properties/LINES.md) | Draw each pair of recorded vertices as an independent line segment. | -| [modifierState](Textmodifier/properties/modifierState.md) | Current modifier key state. | -| [mouse](Textmodifier/properties/mouse.md) | Current mouse position in center-based grid coordinates. | -| [mouseIsPressed](Textmodifier/properties/mouseIsPressed.md) | Whether a mouse button is currently held down. | -| [movedX](Textmodifier/properties/movedX.md) | Horizontal mouse movement accumulated since the previous rendered frame. | -| [movedY](Textmodifier/properties/movedY.md) | Vertical mouse movement accumulated since the previous rendered frame. | -| [pmouse](Textmodifier/properties/pmouse.md) | Mouse position from the previous rendered frame. | -| [POINTS](Textmodifier/properties/POINTS.md) | Draw each recorded vertex as a separate point. | -| [pressedKeys](Textmodifier/properties/pressedKeys.md) | Keys currently being held down. | -| [QUAD\_STRIP](Textmodifier/properties/QUAD_STRIP.md) | Draw paired vertices as a connected strip of quads. | -| [QUADS](Textmodifier/properties/QUADS.md) | Draw each group of four vertices as a quad split into two triangles. | -| [touches](Textmodifier/properties/touches.md) | Currently active touches in grid coordinates. | -| [TRIANGLE\_FAN](Textmodifier/properties/TRIANGLE_FAN.md) | Draw triangles that all share the first recorded vertex. | -| [TRIANGLE\_STRIP](Textmodifier/properties/TRIANGLE_STRIP.md) | Draw overlapping triplets of vertices as a connected triangle strip. | -| [TRIANGLES](Textmodifier/properties/TRIANGLES.md) | Draw each group of three vertices as an independent triangle. | -| [windowHeight](Textmodifier/properties/windowHeight.md) | Current browser window height in pixels. | -| [windowWidth](Textmodifier/properties/windowWidth.md) | Current browser window width in pixels. | +| [layers](Textmodifier/accessors/layers.md) | Layer manager for this Textmodifier instance. | -## Accessors +## Lighting + +Illuminate three-dimensional geometry. + +| Method | Description | +| ------ | ------ | +| [ambientLight](Textmodifier/methods/ambientLight.md) | Add an ambient light using a grayscale value. | +| [lightFalloff](Textmodifier/methods/lightFalloff.md) | Configure distance attenuation used by point lights. | +| [noLights](Textmodifier/methods/noLights.md) | Remove all active lights (ambient and point) and reset light falloff to `(1, 0, 0)`. | +| [pointLight](Textmodifier/methods/pointLight.md) | Add a point light using RGB components and explicit XYZ position. | + +## Loading & errors + +Access built-in loading feedback and fatal-error controls. | Accessor | Description | | ------ | ------ | -| [canvas](Textmodifier/accessors/canvas.md) | Canvas containing the rendered output. | -| [conversions](Textmodifier/accessors/conversions.md) | Access the conversion manager for this Textmodifier instance. | | [errors](Textmodifier/accessors/errors.md) | Built-in fatal error layer controller. | -| [filters](Textmodifier/accessors/filters.md) | Filter manager for this Textmodifier instance. | -| [font](Textmodifier/accessors/font.md) | Font or tileset used by the current drawing layer. | -| [frameCount](Textmodifier/accessors/frameCount.md) | Current frame count. | -| [grid](Textmodifier/accessors/grid.md) | Grid for the layer currently being drawn. | -| [height](Textmodifier/accessors/height.md) | Canvas height in pixels. | -| [isDisposed](Textmodifier/accessors/isDisposed.md) | Whether this instance has been destroyed. | -| [isRenderingFrame](Textmodifier/accessors/isRenderingFrame.md) | Check if rendering is currently in progress for this frame. | -| [layers](Textmodifier/accessors/layers.md) | Layer manager for this Textmodifier instance. | | [loading](Textmodifier/accessors/loading.md) | Built-in loading layer controller. | -| [millis](Textmodifier/accessors/millis.md) | Milliseconds since the sketch started running. | -| [overlay](Textmodifier/accessors/overlay.md) | Overlay source image for the target canvas or video, when overlay mode is enabled. | -| [secs](Textmodifier/accessors/secs.md) | Seconds since the sketch started running. | -| [width](Textmodifier/accessors/width.md) | Canvas width in pixels. | -## Methods +## Math & vectors + +Use creative-coding math helpers and mutable vectors. | Method | Description | | ------ | ------ | | [abs](Textmodifier/methods/abs.md) | Calculate the absolute value of a number. | | [acos](Textmodifier/methods/acos.md) | Calculate the arc cosine of a value. | -| [ambientLight](Textmodifier/methods/ambientLight.md) | Add an ambient light using a grayscale value. | -| [applyMatrix](Textmodifier/methods/applyMatrix.md) | Multiply the current model transform by a custom 4x4 matrix. | -| [arc](Textmodifier/methods/arc.md) | Draw an arc with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | | [asin](Textmodifier/methods/asin.md) | Calculate the arc sine of a value. | | [atan](Textmodifier/methods/atan.md) | Calculate the arc tangent of a value. | | [atan2](Textmodifier/methods/atan2.md) | Calculate the angle from a vector's y and x components. | -| [background](Textmodifier/methods/background.md) | Current background color. | -| [beginShape](Textmodifier/methods/beginShape.md) | Start recording vertices for a custom 2D or 3D shape. Call [vertex](Textmodifier/methods/vertex.md) one or more times, then call [endShape](Textmodifier/methods/endShape.md) to draw the recorded shape. | -| [bezierCurve](Textmodifier/methods/bezierCurve.md) | Draw a smooth cubic Bezier curve between two points. The curve thickness is controlled by the current [lineWeight](Textmodifier/methods/lineWeight.md) setting. | -| [box](Textmodifier/methods/box.md) | Draw a box mesh primitive. | -| [camera](Textmodifier/methods/camera.md) | Set an explicit camera transform for subsequent draw calls. | | [ceil](Textmodifier/methods/ceil.md) | Round up to the closest integer. | -| [cellColor](Textmodifier/methods/cellColor.md) | Current cell background color. | -| [char](Textmodifier/methods/char.md) | Current character string used for drawing. | -| [charColor](Textmodifier/methods/charColor.md) | Current character color. | -| [charRotation](Textmodifier/methods/charRotation.md) | Set the character rotation for subsequent drawing, or get the current angle. | | [clamp](Textmodifier/methods/clamp.md) | Clamp a value between a minimum and maximum range. | -| [clear](Textmodifier/methods/clear.md) | Clear the layer currently drawing to. | -| [color](Textmodifier/methods/color.md) | Create a reusable color object from a grayscale value. | -| [colorMode](Textmodifier/methods/colorMode.md) | Current color interpretation mode. | -| [cone](Textmodifier/methods/cone.md) | Draw a cone mesh primitive. | | [constrain](Textmodifier/methods/constrain.md) | Constrain a value between a minimum and maximum range. | | [cos](Textmodifier/methods/cos.md) | Calculate the cosine of an angle. | -| [createCamera](Textmodifier/methods/createCamera.md) | Create and activate a camera initialized from the current render camera state. | -| [~~createFilterShader~~](Textmodifier/methods/createFilterShader.md) | Create a material shader from fragment shader source or a file path. | -| [createFramebuffer](Textmodifier/methods/createFramebuffer.md) | Create a framebuffer for offscreen rendering. | -| [createGlyphRamp](Textmodifier/methods/createGlyphRamp.md) | Create a reusable glyph ramp from a character sequence. | -| [createMaterialShader](Textmodifier/methods/createMaterialShader.md) | Create a material shader from fragment shader source or a file path. | -| [createShader](Textmodifier/methods/createShader.md) | Create a shader from vertex and fragment source, or from file paths. | -| [createTexture](Textmodifier/methods/createTexture.md) | Create a dynamic texture from an external canvas or video element. | | [createVector](Textmodifier/methods/createVector.md) | Create a mutable vector. | -| [cursor](Textmodifier/methods/cursor.md) | Set the mouse cursor for the textmode canvas. | -| [cylinder](Textmodifier/methods/cylinder.md) | Draw a cylinder mesh primitive. | | [degrees](Textmodifier/methods/degrees.md) | Convert radians to degrees. | -| [deltaTime](Textmodifier/methods/deltaTime.md) | Time in milliseconds between the current frame and the previous frame. | -| [destroy](Textmodifier/methods/destroy.md) | Completely destroy this Textmodifier instance and free all associated resources. | | [dist](Textmodifier/methods/dist.md) | Calculate the Euclidean distance between two points. | -| [doubleClicked](Textmodifier/methods/doubleClicked.md) | Register the single-callback handler for double-clicks. | -| [doubleTap](Textmodifier/methods/doubleTap.md) | Register a callback for double tap gestures. | -| [draw](Textmodifier/methods/draw.md) | Set the base layer draw callback. | | [ease](Textmodifier/methods/ease.md) | Apply an easing curve to a normalized amount. | -| [ellipse](Textmodifier/methods/ellipse.md) | Draw an ellipse with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | -| [ellipsoid](Textmodifier/methods/ellipsoid.md) | Draw an ellipsoid mesh primitive. | -| [endShape](Textmodifier/methods/endShape.md) | Finish the active custom shape and enqueue its geometry. | -| [exitPointerLock](Textmodifier/methods/exitPointerLock.md) | Exit pointer lock if the textmode canvas currently owns it. | | [exp](Textmodifier/methods/exp.md) | Calculate Euler's number raised to a value. | -| [fill](Textmodifier/methods/fill.md) | Alias for [cellColor](Textmodifier/methods/cellColor.md). Current fill (cell background) color. | -| [filter](Textmodifier/methods/filter.md) | Apply a filter to the final composited output. | -| [finalDraw](Textmodifier/methods/finalDraw.md) | Set the final post-processing callback for the composited output. | -| [flipX](Textmodifier/methods/flipX.md) | Toggle horizontal flipping for subsequent characters, or get the current state. | -| [flipY](Textmodifier/methods/flipY.md) | Toggle vertical flipping for subsequent characters, or get the current state. | | [floor](Textmodifier/methods/floor.md) | Round down to the closest integer. | -| [fontSize](Textmodifier/methods/fontSize.md) | Set or get the base layer font size. | | [fract](Textmodifier/methods/fract.md) | Calculate the fractional part of a number. | -| [frameRate](Textmodifier/methods/frameRate.md) | Set the target frame rate, or get the current measured frame rate when called without arguments. | -| [gamepad](Textmodifier/methods/gamepad.md) | Resolve a connected gamepad by its browser-assigned slot index. | -| [gamepadAxisChanged](Textmodifier/methods/gamepadAxisChanged.md) | Register the single-callback handler for meaningful gamepad axis changes. | -| [gamepadButtonPressed](Textmodifier/methods/gamepadButtonPressed.md) | Register the single-callback handler for gamepad button press events. | -| [gamepadButtonReleased](Textmodifier/methods/gamepadButtonReleased.md) | Register the single-callback handler for gamepad button release events. | -| [gamepadConnected](Textmodifier/methods/gamepadConnected.md) | Register the single-callback handler for gamepad connection events. | -| [gamepadDisconnected](Textmodifier/methods/gamepadDisconnected.md) | Register the single-callback handler for gamepad disconnection events. | -| [image](Textmodifier/methods/image.md) | Draw a framebuffer, image, video, or texture source to the currently bound framebuffer. | -| [inputGrid](Textmodifier/methods/inputGrid.md) | Get or set the grid used for mouse and touch coordinate mapping. | -| [invert](Textmodifier/methods/invert.md) | Toggle character/cell color inversion, or get the current state. | -| [isKeyPressed](Textmodifier/methods/isKeyPressed.md) | Check whether a key is currently pressed. | -| [isLooping](Textmodifier/methods/isLooping.md) | Whether the automatic render loop is currently running. | -| [keyPressed](Textmodifier/methods/keyPressed.md) | Register the single-callback handler for key press events. | -| [keyReleased](Textmodifier/methods/keyReleased.md) | Register the single-callback handler for key release events. | -| [keyTyped](Textmodifier/methods/keyTyped.md) | Register the single-callback handler for printable character input. | | [lerp](Textmodifier/methods/lerp.md) | Linear interpolation between two values. | -| [lightFalloff](Textmodifier/methods/lightFalloff.md) | Configure distance attenuation used by point lights. | -| [line](Textmodifier/methods/line.md) | Draw a line from `(x1, y1)` to `(x2, y2)`. | -| [lineWeight](Textmodifier/methods/lineWeight.md) | Set or get line thickness for subsequent line and curve drawing. | -| [loadFont](Textmodifier/methods/loadFont.md) | Load a font and optionally set it as the base layer's active font. | -| [loadImage](Textmodifier/methods/loadImage.md) | Load an image source that can be drawn with [image](Textmodifier/methods/image.md). | -| [loadTileset](Textmodifier/methods/loadTileset.md) | Load a tileset and optionally set it as the base layer's active glyph source. | -| [loadVideo](Textmodifier/methods/loadVideo.md) | Load a video source that can be drawn with [image](Textmodifier/methods/image.md). | | [log](Textmodifier/methods/log.md) | Calculate the natural logarithm of a value. | -| [longPress](Textmodifier/methods/longPress.md) | Register a callback for long press gestures. | -| [lookAt](Textmodifier/methods/lookAt.md) | Update the look-at target and optional up vector for the active camera. | -| [loop](Textmodifier/methods/loop.md) | Resume the rendering loop if it was stopped by [noLoop](Textmodifier/methods/noLoop.md). | | [map](Textmodifier/methods/map.md) | Re-map a number from one range to another. | | [max](Textmodifier/methods/max.md) | Return the largest value in a sequence. | | [min](Textmodifier/methods/min.md) | Return the smallest value in a sequence. | +| [norm](Textmodifier/methods/norm.md) | Map a number from a range to a normalized 0 to 1 range. | +| [pow](Textmodifier/methods/pow.md) | Raise a base value to an exponent. | +| [radians](Textmodifier/methods/radians.md) | Convert degrees to radians. | +| [round](Textmodifier/methods/round.md) | Round to the closest integer or decimal place. | +| [sin](Textmodifier/methods/sin.md) | Calculate the sine of an angle. | +| [sq](Textmodifier/methods/sq.md) | Square a number. | +| [sqrt](Textmodifier/methods/sqrt.md) | Calculate the square root of a number. | +| [tan](Textmodifier/methods/tan.md) | Calculate the tangent of an angle. | + +## Media & textures + +Load visual sources and use them as drawing or texture input. + +| Method | Description | +| ------ | ------ | +| [createTexture](Textmodifier/methods/createTexture.md) | Create a dynamic texture from an external canvas or video element. | +| [image](Textmodifier/methods/image.md) | Draw a framebuffer, image, video, or texture source to the currently bound framebuffer. | +| [loadImage](Textmodifier/methods/loadImage.md) | Load an image source that can be drawn with [image](Textmodifier/methods/image.md). | +| [loadVideo](Textmodifier/methods/loadVideo.md) | Load a video source that can be drawn with [image](Textmodifier/methods/image.md). | +| [noTexture](Textmodifier/methods/noTexture.md) | Clear the active texture for later geometry draws. | +| [texture](Textmodifier/methods/texture.md) | Bind a media source or framebuffer as the texture for later geometry draws. | + +## Mouse input + +Read pointer state, mouse events, and pointer-lock controls. + +| Name | Description | +| ------ | ------ | +| [mouse](Textmodifier/properties/mouse.md) | Current mouse position in center-based grid coordinates. | +| [mouseIsPressed](Textmodifier/properties/mouseIsPressed.md) | Whether a mouse button is currently held down. | +| [movedX](Textmodifier/properties/movedX.md) | Horizontal mouse movement accumulated since the previous rendered frame. | +| [movedY](Textmodifier/properties/movedY.md) | Vertical mouse movement accumulated since the previous rendered frame. | +| [pmouse](Textmodifier/properties/pmouse.md) | Mouse position from the previous rendered frame. | +| [cursor](Textmodifier/methods/cursor.md) | Set the mouse cursor for the textmode canvas. | +| [doubleClicked](Textmodifier/methods/doubleClicked.md) | Register the single-callback handler for double-clicks. | +| [exitPointerLock](Textmodifier/methods/exitPointerLock.md) | Exit pointer lock if the textmode canvas currently owns it. | | [mouseClicked](Textmodifier/methods/mouseClicked.md) | Register the single-callback handler for mouse clicks. | | [mouseDragged](Textmodifier/methods/mouseDragged.md) | Register the single-callback handler for mouse dragging. | | [mouseMoved](Textmodifier/methods/mouseMoved.md) | Register the single-callback handler for mouse movement. | | [mousePressed](Textmodifier/methods/mousePressed.md) | Register the single-callback handler for mouse press events. | | [mouseReleased](Textmodifier/methods/mouseReleased.md) | Register the single-callback handler for mouse release events. | | [mouseScrolled](Textmodifier/methods/mouseScrolled.md) | Register the single-callback handler for mouse wheel scrolling. | +| [requestPointerLock](Textmodifier/methods/requestPointerLock.md) | Request browser pointer lock for the textmode canvas. | + +## Randomness & noise + +Generate deterministic random values and coherent noise. + +| Method | Description | +| ------ | ------ | | [noise](Textmodifier/methods/noise.md) | Return deterministic multi-octave noise for a coordinate. | | [noiseDetail](Textmodifier/methods/noiseDetail.md) | Adjust noise octaves and falloff. | | [noiseSeed](Textmodifier/methods/noiseSeed.md) | Reset the noise lookup table to a seed. | -| [noLights](Textmodifier/methods/noLights.md) | Remove all active lights (ambient and point) and reset light falloff to `(1, 0, 0)`. | -| [noLoop](Textmodifier/methods/noLoop.md) | Stop the automatic rendering loop. | -| [norm](Textmodifier/methods/norm.md) | Map a number from a range to a normalized 0 to 1 range. | -| [noTexture](Textmodifier/methods/noTexture.md) | Clear the active texture for later geometry draws. | -| [off](Textmodifier/methods/off.md) | Remove a previously registered input event listener. | -| [on](Textmodifier/methods/on.md) | Register an input event listener. | -| [once](Textmodifier/methods/once.md) | Register an input event listener that removes itself after the first invocation. | -| [ortho](Textmodifier/methods/ortho.md) | Enable orthographic projection for subsequent shape drawing. | -| [perspective](Textmodifier/methods/perspective.md) | Enable perspective projection and optionally set projection parameters. | -| [pinch](Textmodifier/methods/pinch.md) | Register a callback for pinch gestures, receiving scale deltas. | -| [pixelDensity](Textmodifier/methods/pixelDensity.md) | Get the current pixel density for HiDPI rendering. | -| [point](Textmodifier/methods/point.md) | Draw one cell with the current settings. | -| [pointLight](Textmodifier/methods/pointLight.md) | Add a point light using RGB components and explicit XYZ position. | -| [pop](Textmodifier/methods/pop.md) | Restore the most recently saved rendering state from the state stack. Use with [push](Textmodifier/methods/push.md) to isolate style changes within a block. | -| [postDraw](Textmodifier/methods/postDraw.md) | Set the base layer post-draw callback. | -| [pow](Textmodifier/methods/pow.md) | Raise a base value to an exponent. | -| [print](Textmodifier/methods/print.md) | Print a string of text onto the active drawing layer. | -| [printAlign](Textmodifier/methods/printAlign.md) | Sets the text alignment rules for subsequent `print` calls. | -| [push](Textmodifier/methods/push.md) | Save the current rendering state to the state stack. Use with [pop](Textmodifier/methods/pop.md) to isolate style changes within a block. | -| [radians](Textmodifier/methods/radians.md) | Convert degrees to radians. | | [random](Textmodifier/methods/random.md) | Return a random number from 0 up to, but not including, 1. | | [randomGaussian](Textmodifier/methods/randomGaussian.md) | Return a normally distributed random number. | | [randomSeed](Textmodifier/methods/randomSeed.md) | Reset the main sketch random generator to a seed. | | [randomStream](Textmodifier/methods/randomStream.md) | Get an independent deterministic random stream for a name. | -| [rect](Textmodifier/methods/rect.md) | Draw a rectangle with the current settings. Position is controlled via [translate](Textmodifier/methods/translate.md), [push](Textmodifier/methods/push.md), and [pop](Textmodifier/methods/pop.md). | -| [redraw](Textmodifier/methods/redraw.md) | Render a fixed number of frames on demand. | -| [requestPointerLock](Textmodifier/methods/requestPointerLock.md) | Request browser pointer lock for the textmode canvas. | -| [resetCamera](Textmodifier/methods/resetCamera.md) | Reset to the default auto camera behavior. | -| [resetMatrix](Textmodifier/methods/resetMatrix.md) | Reset the current model transform to identity. | + +## Shaders & framebuffers + +Build GPU effects and offscreen rendering pipelines. + +| Method | Description | +| ------ | ------ | +| [createFramebuffer](Textmodifier/methods/createFramebuffer.md) | Create a framebuffer for offscreen rendering. | +| [createMaterialShader](Textmodifier/methods/createMaterialShader.md) | Create a material shader from fragment shader source or a file path. | +| [createShader](Textmodifier/methods/createShader.md) | Create a shader from vertex and fragment source, or from file paths. | | [resetShader](Textmodifier/methods/resetShader.md) | Reset the current shader to the default solid color shader. | -| [resizeCanvas](Textmodifier/methods/resizeCanvas.md) | Resize the canvas and adjust all related components accordingly. | -| [rotate](Textmodifier/methods/rotate.md) | Set rotation for subsequent shape drawing. | -| [rotateGesture](Textmodifier/methods/rotateGesture.md) | Register a callback for rotate gestures, receiving rotation deltas in degrees. | -| [rotateX](Textmodifier/methods/rotateX.md) | Set X-axis rotation for subsequent shape drawing, or get the current angle. | -| [rotateY](Textmodifier/methods/rotateY.md) | Set Y-axis rotation for subsequent shape drawing, or get the current angle. | -| [rotateZ](Textmodifier/methods/rotateZ.md) | Set Z-axis rotation for subsequent shape drawing, or get the current angle. | -| [round](Textmodifier/methods/round.md) | Round to the closest integer or decimal place. | -| [scale](Textmodifier/methods/scale.md) | Scale subsequent geometry in model space. | -| [setCamera](Textmodifier/methods/setCamera.md) | Activate a previously created camera object. | | [setUniform](Textmodifier/methods/setUniform.md) | Set a uniform value on the current custom shader. | | [setUniforms](Textmodifier/methods/setUniforms.md) | Set multiple uniform values on the current custom shader. | -| [setup](Textmodifier/methods/setup.md) | Set the setup callback that runs once initialization is complete. | | [shader](Textmodifier/methods/shader.md) | Set a custom shader for subsequent drawing operations. | -| [sin](Textmodifier/methods/sin.md) | Calculate the sine of an angle. | -| [sphere](Textmodifier/methods/sphere.md) | Draw a sphere mesh primitive. | -| [sq](Textmodifier/methods/sq.md) | Square a number. | -| [sqrt](Textmodifier/methods/sqrt.md) | Calculate the square root of a number. | -| [stroke](Textmodifier/methods/stroke.md) | Alias for [charColor](Textmodifier/methods/charColor.md). Current stroke (character) color. | + +## Sketch lifecycle + +Configure callbacks and manage the lifetime of a sketch. + +| Name | Description | +| ------ | ------ | +| [isDisposed](Textmodifier/accessors/isDisposed.md) | Whether this instance has been destroyed. | +| [isRenderingFrame](Textmodifier/accessors/isRenderingFrame.md) | Check if rendering is currently in progress for this frame. | +| [destroy](Textmodifier/methods/destroy.md) | Completely destroy this Textmodifier instance and free all associated resources. | +| [draw](Textmodifier/methods/draw.md) | Set the base layer draw callback. | +| [finalDraw](Textmodifier/methods/finalDraw.md) | Set the final post-processing callback for the composited output. | +| [postDraw](Textmodifier/methods/postDraw.md) | Set the base layer post-draw callback. | +| [setup](Textmodifier/methods/setup.md) | Set the setup callback that runs once initialization is complete. | + +## Text rendering + +Lay out and draw strings on the active layer. + +| Method | Description | +| ------ | ------ | +| [print](Textmodifier/methods/print.md) | Print a string of text onto the active drawing layer. | +| [printAlign](Textmodifier/methods/printAlign.md) | Sets the text alignment rules for subsequent `print` calls. | + +## Touch & gestures + +React to touch lifecycle events and derived gestures. + +| Name | Description | +| ------ | ------ | +| [touches](Textmodifier/properties/touches.md) | Currently active touches in grid coordinates. | +| [doubleTap](Textmodifier/methods/doubleTap.md) | Register a callback for double tap gestures. | +| [longPress](Textmodifier/methods/longPress.md) | Register a callback for long press gestures. | +| [pinch](Textmodifier/methods/pinch.md) | Register a callback for pinch gestures, receiving scale deltas. | +| [rotateGesture](Textmodifier/methods/rotateGesture.md) | Register a callback for rotate gestures, receiving rotation deltas in degrees. | | [swipe](Textmodifier/methods/swipe.md) | Register a callback for swipe gestures. | -| [tan](Textmodifier/methods/tan.md) | Calculate the tangent of an angle. | | [tap](Textmodifier/methods/tap.md) | Register a callback for tap gestures. | -| [targetFrameRate](Textmodifier/methods/targetFrameRate.md) | Set or get the target frame rate limit. | -| [texture](Textmodifier/methods/texture.md) | Bind a media source or framebuffer as the texture for later geometry draws. | -| [torus](Textmodifier/methods/torus.md) | Draw a torus mesh primitive. | | [touchCancelled](Textmodifier/methods/touchCancelled.md) | Register the single-callback handler for browser-cancelled touches. | | [touchEnded](Textmodifier/methods/touchEnded.md) | Register the single-callback handler for touch end events. | | [touchMoved](Textmodifier/methods/touchMoved.md) | Register the single-callback handler for touch movement. | | [touchStarted](Textmodifier/methods/touchStarted.md) | Register the single-callback handler for touch start events. | + +## Transforms & state + +Position geometry and isolate changes to draw state. + +| Method | Description | +| ------ | ------ | +| [applyMatrix](Textmodifier/methods/applyMatrix.md) | Multiply the current model transform by a custom 4x4 matrix. | +| [pop](Textmodifier/methods/pop.md) | Restore the most recently saved rendering state from the state stack. Use with [push](Textmodifier/methods/push.md) to isolate style changes within a block. | +| [push](Textmodifier/methods/push.md) | Save the current rendering state to the state stack. Use with [pop](Textmodifier/methods/pop.md) to isolate style changes within a block. | +| [resetMatrix](Textmodifier/methods/resetMatrix.md) | Reset the current model transform to identity. | +| [rotate](Textmodifier/methods/rotate.md) | Set rotation for subsequent shape drawing. | +| [rotateX](Textmodifier/methods/rotateX.md) | Set X-axis rotation for subsequent shape drawing, or get the current angle. | +| [rotateY](Textmodifier/methods/rotateY.md) | Set Y-axis rotation for subsequent shape drawing, or get the current angle. | +| [rotateZ](Textmodifier/methods/rotateZ.md) | Set Z-axis rotation for subsequent shape drawing, or get the current angle. | +| [scale](Textmodifier/methods/scale.md) | Scale subsequent geometry in model space. | | [translate](Textmodifier/methods/translate.md) | Translate subsequent shape drawing. | | [translateX](Textmodifier/methods/translateX.md) | Current accumulated X-axis translation. | | [translateY](Textmodifier/methods/translateY.md) | Current accumulated Y-axis translation. | | [translateZ](Textmodifier/methods/translateZ.md) | Current accumulated Z-axis translation. | -| [triangle](Textmodifier/methods/triangle.md) | Draw a triangle with the current settings. | -| [useTileColors](Textmodifier/methods/useTileColors.md) | Configure authored tileset color preservation on the base layer. | -| [vertex](Textmodifier/methods/vertex.md) | Add a vertex to the active custom shape. The current transform, character, color, and line state are captured for this vertex. | -| [windowResized](Textmodifier/methods/windowResized.md) | Set the callback that runs after a window resize. | diff --git a/api/textmode.js/classes/Textmodifier/accessors/canvas.md b/api/textmode.js/classes/Textmodifier/accessors/canvas.md index 87d7817e..ab71227a 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/canvas.md +++ b/api/textmode.js/classes/Textmodifier/accessors/canvas.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / canvas @@ -28,5 +28,5 @@ Canvas containing the rendered output. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/conversions.md b/api/textmode.js/classes/Textmodifier/accessors/conversions.md index ea2c26a0..22334e5b 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/conversions.md +++ b/api/textmode.js/classes/Textmodifier/accessors/conversions.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / conversions diff --git a/api/textmode.js/classes/Textmodifier/accessors/errors.md b/api/textmode.js/classes/Textmodifier/accessors/errors.md index e53a6bfb..349469de 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/errors.md +++ b/api/textmode.js/classes/Textmodifier/accessors/errors.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / errors @@ -28,5 +28,5 @@ Built-in fatal error layer controller. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/filters.md b/api/textmode.js/classes/Textmodifier/accessors/filters.md index 522085b3..e4a3e764 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/filters.md +++ b/api/textmode.js/classes/Textmodifier/accessors/filters.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / filters diff --git a/api/textmode.js/classes/Textmodifier/accessors/font.md b/api/textmode.js/classes/Textmodifier/accessors/font.md index 24542d3e..100641ae 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/font.md +++ b/api/textmode.js/classes/Textmodifier/accessors/font.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / font @@ -17,7 +17,7 @@ lastModified: 2026-07-31 ## Get Signature ```ts -get font(): +get font(): | TextmodeFont | TextmodeTileset; ``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md index 555a899b..36dfa29c 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/frameCount.md +++ b/api/textmode.js/classes/Textmodifier/accessors/frameCount.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / frameCount @@ -35,7 +35,7 @@ Number of frames rendered since the sketch started. ### Example - + ## Set Signature @@ -60,5 +60,5 @@ point in time-based patterns. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/grid.md b/api/textmode.js/classes/Textmodifier/accessors/grid.md index f2e51333..d5b6781b 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/grid.md +++ b/api/textmode.js/classes/Textmodifier/accessors/grid.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / grid @@ -32,5 +32,5 @@ If no grid is set (e.g., before user setup()), returns `undefined`. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/height.md b/api/textmode.js/classes/Textmodifier/accessors/height.md index d21c95ea..43fea58a 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/height.md +++ b/api/textmode.js/classes/Textmodifier/accessors/height.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / height @@ -28,5 +28,5 @@ Canvas height in pixels. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md index 3220b3fb..955761f9 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / isDisposed @@ -28,5 +28,5 @@ Whether this instance has been destroyed. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md index ca385eac..687c84ba 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md +++ b/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / isRenderingFrame @@ -28,5 +28,5 @@ Check if rendering is currently in progress for this frame. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/layers.md b/api/textmode.js/classes/Textmodifier/accessors/layers.md index 9cce2b55..6356b432 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/layers.md +++ b/api/textmode.js/classes/Textmodifier/accessors/layers.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / layers diff --git a/api/textmode.js/classes/Textmodifier/accessors/loading.md b/api/textmode.js/classes/Textmodifier/accessors/loading.md index 6d89cb03..691c3ee3 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/loading.md +++ b/api/textmode.js/classes/Textmodifier/accessors/loading.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loading diff --git a/api/textmode.js/classes/Textmodifier/accessors/millis.md b/api/textmode.js/classes/Textmodifier/accessors/millis.md index e9b50702..732f545d 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/millis.md +++ b/api/textmode.js/classes/Textmodifier/accessors/millis.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / millis @@ -39,11 +39,11 @@ Milliseconds since the sketch started. ### Examples - + - + - + ## Set Signature @@ -68,5 +68,5 @@ affect the value returned by [secs](secs.md) since they are connected. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/overlay.md b/api/textmode.js/classes/Textmodifier/accessors/overlay.md index 256d147a..46760dea 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/overlay.md +++ b/api/textmode.js/classes/Textmodifier/accessors/overlay.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / overlay @@ -17,7 +17,7 @@ lastModified: 2026-07-31 ## Get Signature ```ts -get overlay(): +get overlay(): | TextmodeImage | undefined; ``` diff --git a/api/textmode.js/classes/Textmodifier/accessors/secs.md b/api/textmode.js/classes/Textmodifier/accessors/secs.md index cd59966f..c2a04b67 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/secs.md +++ b/api/textmode.js/classes/Textmodifier/accessors/secs.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / secs @@ -38,9 +38,9 @@ Seconds since the sketch started. ### Examples - + - + ## Set Signature @@ -65,5 +65,5 @@ affect the value returned by [millis](millis.md) since they are connected. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/accessors/width.md b/api/textmode.js/classes/Textmodifier/accessors/width.md index 5b7d997b..a9360993 100644 --- a/api/textmode.js/classes/Textmodifier/accessors/width.md +++ b/api/textmode.js/classes/Textmodifier/accessors/width.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: Textmodifier kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / width @@ -28,5 +28,5 @@ Canvas width in pixels. ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/abs.md b/api/textmode.js/classes/Textmodifier/methods/abs.md index c7e97159..83f167a2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/abs.md +++ b/api/textmode.js/classes/Textmodifier/methods/abs.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / abs diff --git a/api/textmode.js/classes/Textmodifier/methods/acos.md b/api/textmode.js/classes/Textmodifier/methods/acos.md index 0b469273..e898b182 100644 --- a/api/textmode.js/classes/Textmodifier/methods/acos.md +++ b/api/textmode.js/classes/Textmodifier/methods/acos.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / acos diff --git a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md index 290eada5..2cc1f404 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ambientLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/ambientLight.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ambientLight @@ -65,8 +65,8 @@ Add an ambient light using a grayscale value and alpha. ```ts ambientLight( - v1, - v2, + v1, + v2, v3): void; ``` @@ -89,9 +89,9 @@ Add an ambient light using RGB components. ```ts ambientLight( - v1, - v2, - v3, + v1, + v2, + v3, alpha): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md index 2e739e3d..54409578 100644 --- a/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / applyMatrix @@ -42,21 +42,21 @@ Current implementation supports affine TRS-style matrices (no perspective/shear) ```ts applyMatrix( - m00, - m01, - m02, - m03, - m10, - m11, - m12, - m13, - m20, - m21, - m22, - m23, - m30, - m31, - m32, + m00, + m01, + m02, + m03, + m10, + m11, + m12, + m13, + m20, + m21, + m22, + m23, + m30, + m31, + m32, m33): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/arc.md b/api/textmode.js/classes/Textmodifier/methods/arc.md index 0f3d4ca8..83f4cea7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/arc.md +++ b/api/textmode.js/classes/Textmodifier/methods/arc.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / arc @@ -16,9 +16,9 @@ lastModified: 2026-07-31 ```ts arc( - width, - height, - startAngle, + width, + height, + startAngle, endAngle): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/asin.md b/api/textmode.js/classes/Textmodifier/methods/asin.md index ae850bc9..022679b7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/asin.md +++ b/api/textmode.js/classes/Textmodifier/methods/asin.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / asin diff --git a/api/textmode.js/classes/Textmodifier/methods/atan.md b/api/textmode.js/classes/Textmodifier/methods/atan.md index d0af2c41..1fce1abf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / atan diff --git a/api/textmode.js/classes/Textmodifier/methods/atan2.md b/api/textmode.js/classes/Textmodifier/methods/atan2.md index 88e5c82a..e2cce943 100644 --- a/api/textmode.js/classes/Textmodifier/methods/atan2.md +++ b/api/textmode.js/classes/Textmodifier/methods/atan2.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / atan2 diff --git a/api/textmode.js/classes/Textmodifier/methods/background.md b/api/textmode.js/classes/Textmodifier/methods/background.md index 4e43d495..9226ef83 100644 --- a/api/textmode.js/classes/Textmodifier/methods/background.md +++ b/api/textmode.js/classes/Textmodifier/methods/background.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / background @@ -59,9 +59,9 @@ Set the background color using a grayscale value. ```ts background( - r, - g, - b, + r, + g, + b, a?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/beginShape.md b/api/textmode.js/classes/Textmodifier/methods/beginShape.md index 36cd1458..99ea7cb8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/beginShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/beginShape.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / beginShape diff --git a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md index 9c1dddd0..312a065c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md +++ b/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / bezierCurve @@ -16,13 +16,13 @@ lastModified: 2026-07-31 ```ts bezierCurve( - x1, - y1, - cp1x, - cp1y, - cp2x, - cp2y, - x2, + x1, + y1, + cp1x, + cp1y, + cp2x, + cp2y, + x2, y2): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/box.md b/api/textmode.js/classes/Textmodifier/methods/box.md index 727df7a6..6cdf9bd3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/box.md +++ b/api/textmode.js/classes/Textmodifier/methods/box.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / box @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts box( - width?, - height?, + width?, + height?, depth?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/camera.md b/api/textmode.js/classes/Textmodifier/methods/camera.md index 7ed9d365..86712aa5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/camera.md +++ b/api/textmode.js/classes/Textmodifier/methods/camera.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / camera @@ -16,14 +16,14 @@ lastModified: 2026-07-31 ```ts camera( - eyeX, - eyeY, - eyeZ, - targetX?, - targetY?, - targetZ?, - upX?, - upY?, + eyeX, + eyeY, + eyeZ, + targetX?, + targetY?, + targetZ?, + upX?, + upY?, upZ?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/ceil.md b/api/textmode.js/classes/Textmodifier/methods/ceil.md index 8933adcb..87dcc85e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ceil.md +++ b/api/textmode.js/classes/Textmodifier/methods/ceil.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ceil diff --git a/api/textmode.js/classes/Textmodifier/methods/cellColor.md b/api/textmode.js/classes/Textmodifier/methods/cellColor.md index 5e9bd742..da3c9d32 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cellColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cellColor.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / cellColor @@ -59,9 +59,9 @@ Set the cell background color using a grayscale value. ```ts cellColor( - r, - g, - b, + r, + g, + b, a?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/char.md b/api/textmode.js/classes/Textmodifier/methods/char.md index aad5b9dc..299c49ef 100644 --- a/api/textmode.js/classes/Textmodifier/methods/char.md +++ b/api/textmode.js/classes/Textmodifier/methods/char.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / char diff --git a/api/textmode.js/classes/Textmodifier/methods/charColor.md b/api/textmode.js/classes/Textmodifier/methods/charColor.md index d76fffa8..6567f6c4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charColor.md +++ b/api/textmode.js/classes/Textmodifier/methods/charColor.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / charColor @@ -59,9 +59,9 @@ Set the character color using a grayscale value. ```ts charColor( - r, - g, - b, + r, + g, + b, a?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/charRotation.md b/api/textmode.js/classes/Textmodifier/methods/charRotation.md index 42ba0b81..e0073027 100644 --- a/api/textmode.js/classes/Textmodifier/methods/charRotation.md +++ b/api/textmode.js/classes/Textmodifier/methods/charRotation.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / charRotation diff --git a/api/textmode.js/classes/Textmodifier/methods/clamp.md b/api/textmode.js/classes/Textmodifier/methods/clamp.md index ef560d34..f1ed2d97 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/clamp.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / clamp @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts clamp( - value, - low, + value, + low, high): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/clear.md b/api/textmode.js/classes/Textmodifier/methods/clear.md index 3cb7ad90..b3e7ae1d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/clear.md +++ b/api/textmode.js/classes/Textmodifier/methods/clear.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / clear diff --git a/api/textmode.js/classes/Textmodifier/methods/color.md b/api/textmode.js/classes/Textmodifier/methods/color.md index 1d5c2dd8..9eb5faae 100644 --- a/api/textmode.js/classes/Textmodifier/methods/color.md +++ b/api/textmode.js/classes/Textmodifier/methods/color.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / color @@ -43,9 +43,9 @@ A TextmodeColor instance ```ts color( - r, - g, - b, + r, + g, + b, a?): TextmodeColor; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/colorMode.md b/api/textmode.js/classes/Textmodifier/methods/colorMode.md index b9bab9bf..7b293f98 100644 --- a/api/textmode.js/classes/Textmodifier/methods/colorMode.md +++ b/api/textmode.js/classes/Textmodifier/methods/colorMode.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / colorMode @@ -63,10 +63,10 @@ alpha, defaulting to the selected mode's alpha max. ```ts colorMode( - mode, - max1, - max2, - max3, + mode, + max1, + max2, + max3, maxA?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cone.md b/api/textmode.js/classes/Textmodifier/methods/cone.md index d7fb7e06..d27395d1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cone.md +++ b/api/textmode.js/classes/Textmodifier/methods/cone.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / cone diff --git a/api/textmode.js/classes/Textmodifier/methods/constrain.md b/api/textmode.js/classes/Textmodifier/methods/constrain.md index cdb8d3d0..91faa46e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/constrain.md +++ b/api/textmode.js/classes/Textmodifier/methods/constrain.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / constrain @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts constrain( - value, - low, + value, + low, high): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cos.md b/api/textmode.js/classes/Textmodifier/methods/cos.md index e7c27268..8649947e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cos.md +++ b/api/textmode.js/classes/Textmodifier/methods/cos.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / cos diff --git a/api/textmode.js/classes/Textmodifier/methods/createCamera.md b/api/textmode.js/classes/Textmodifier/methods/createCamera.md index ea025dd7..eea5b5b2 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/createCamera.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createCamera diff --git a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md b/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md deleted file mode 100644 index d493c89a..00000000 --- a/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: doc -editLink: true -title: createFilterShader -description: Create a material shader from fragment shader source or a file path. -category: Methods -api: true -owner: Textmodifier -kind: Method -lastModified: 2026-07-31 ---- - -[textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createFilterShader - -# ~~Method: createFilterShader()~~ - -```ts -createFilterShader(fragmentSource): Promise; -``` - -Create a material shader from fragment shader source or a file path. - -## Parameters - -| Parameter | Type | Description | -| ------ | ------ | ------ | -| `fragmentSource` | `string` | Fragment shader source or file path (e.g. './shader.frag'). | - -## Returns - -`Promise`\<[`TextmodeShader`](../../TextmodeShader.md)\> - -A compiled shader ready for use with [shader](shader.md). - -## Deprecated - -Use [createMaterialShader](createMaterialShader.md) for geometry shaders, or `filters.register()` -to register a postprocess filter. - -This compatibility alias creates a fragment-only geometry shader for use with -[shader](shader.md); it does not register a postprocess filter for [filter](filter.md). - -## Example - - - diff --git a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md index 0c8d0353..70bc1d46 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md +++ b/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createFramebuffer diff --git a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md index 7bee4320..857c1c9f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md +++ b/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createGlyphRamp diff --git a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md index d9d2951e..2225c9c7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createMaterialShader diff --git a/api/textmode.js/classes/Textmodifier/methods/createShader.md b/api/textmode.js/classes/Textmodifier/methods/createShader.md index bd8671ae..ce3dc361 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/createShader.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createShader diff --git a/api/textmode.js/classes/Textmodifier/methods/createTexture.md b/api/textmode.js/classes/Textmodifier/methods/createTexture.md index 7489a406..cfa030fe 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/createTexture.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createTexture diff --git a/api/textmode.js/classes/Textmodifier/methods/createVector.md b/api/textmode.js/classes/Textmodifier/methods/createVector.md index 655d8f95..0bf0515e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/createVector.md +++ b/api/textmode.js/classes/Textmodifier/methods/createVector.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / createVector @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts createVector( - x?, - y?, + x?, + y?, z?): TextmodeVector; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/cursor.md b/api/textmode.js/classes/Textmodifier/methods/cursor.md index 460d0d66..c23fcf17 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cursor.md +++ b/api/textmode.js/classes/Textmodifier/methods/cursor.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / cursor diff --git a/api/textmode.js/classes/Textmodifier/methods/cylinder.md b/api/textmode.js/classes/Textmodifier/methods/cylinder.md index ed72d96d..77091b94 100644 --- a/api/textmode.js/classes/Textmodifier/methods/cylinder.md +++ b/api/textmode.js/classes/Textmodifier/methods/cylinder.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / cylinder diff --git a/api/textmode.js/classes/Textmodifier/methods/degrees.md b/api/textmode.js/classes/Textmodifier/methods/degrees.md index 106c8750..ac374326 100644 --- a/api/textmode.js/classes/Textmodifier/methods/degrees.md +++ b/api/textmode.js/classes/Textmodifier/methods/degrees.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / degrees diff --git a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md index a6411882..6a550d26 100644 --- a/api/textmode.js/classes/Textmodifier/methods/deltaTime.md +++ b/api/textmode.js/classes/Textmodifier/methods/deltaTime.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / deltaTime @@ -32,5 +32,5 @@ Milliseconds elapsed since the previous frame. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/destroy.md b/api/textmode.js/classes/Textmodifier/methods/destroy.md index a2f192e5..6116b0c5 100644 --- a/api/textmode.js/classes/Textmodifier/methods/destroy.md +++ b/api/textmode.js/classes/Textmodifier/methods/destroy.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / destroy @@ -28,5 +28,5 @@ After calling this method, the instance should not be used and will be eligible ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/dist.md b/api/textmode.js/classes/Textmodifier/methods/dist.md index bdb7918b..ef65490b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/dist.md +++ b/api/textmode.js/classes/Textmodifier/methods/dist.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / dist @@ -16,9 +16,9 @@ lastModified: 2026-07-31 ```ts dist( - x1, - y1, - x2, + x1, + y1, + x2, y2): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md index 44dea05a..49507487 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / doubleClicked @@ -32,5 +32,5 @@ Register the single-callback handler for double-clicks. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md index d1260599..a0828404 100644 --- a/api/textmode.js/classes/Textmodifier/methods/doubleTap.md +++ b/api/textmode.js/classes/Textmodifier/methods/doubleTap.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / doubleTap diff --git a/api/textmode.js/classes/Textmodifier/methods/draw.md b/api/textmode.js/classes/Textmodifier/methods/draw.md index 61ff2992..67fcabb7 100644 --- a/api/textmode.js/classes/Textmodifier/methods/draw.md +++ b/api/textmode.js/classes/Textmodifier/methods/draw.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / draw @@ -42,5 +42,5 @@ textmodifier.layers.base.draw(callback); ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/ease.md b/api/textmode.js/classes/Textmodifier/methods/ease.md index 08eaf542..0e3cfa30 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ease.md +++ b/api/textmode.js/classes/Textmodifier/methods/ease.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ease diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipse.md b/api/textmode.js/classes/Textmodifier/methods/ellipse.md index ae828663..5151aa80 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipse.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipse.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ellipse diff --git a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md index 4af57e96..10f07c58 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md +++ b/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ellipsoid @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts ellipsoid( - radiusX?, - radiusY?, + radiusX?, + radiusY?, radiusZ?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/endShape.md b/api/textmode.js/classes/Textmodifier/methods/endShape.md index 6f9cc4ba..ebe180c1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/endShape.md +++ b/api/textmode.js/classes/Textmodifier/methods/endShape.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / endShape diff --git a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md index 1ec4775b..c85701d1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / exitPointerLock diff --git a/api/textmode.js/classes/Textmodifier/methods/exp.md b/api/textmode.js/classes/Textmodifier/methods/exp.md index 7891ce14..4a470c0b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/exp.md +++ b/api/textmode.js/classes/Textmodifier/methods/exp.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / exp diff --git a/api/textmode.js/classes/Textmodifier/methods/fill.md b/api/textmode.js/classes/Textmodifier/methods/fill.md index 1de85fe5..cb2ea752 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fill.md +++ b/api/textmode.js/classes/Textmodifier/methods/fill.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / fill @@ -59,9 +59,9 @@ Alias for [cellColor](cellColor.md). Set the fill (cell background) color using ```ts fill( - r, - g, - b, + r, + g, + b, a?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/filter.md b/api/textmode.js/classes/Textmodifier/methods/filter.md index 1673ab3b..2bc6b3b4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/filter.md +++ b/api/textmode.js/classes/Textmodifier/methods/filter.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / filter diff --git a/api/textmode.js/classes/Textmodifier/methods/finalDraw.md b/api/textmode.js/classes/Textmodifier/methods/finalDraw.md index f7a94993..2aace977 100644 --- a/api/textmode.js/classes/Textmodifier/methods/finalDraw.md +++ b/api/textmode.js/classes/Textmodifier/methods/finalDraw.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / finalDraw diff --git a/api/textmode.js/classes/Textmodifier/methods/flipX.md b/api/textmode.js/classes/Textmodifier/methods/flipX.md index 1279b591..10bda242 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipX.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipX.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / flipX diff --git a/api/textmode.js/classes/Textmodifier/methods/flipY.md b/api/textmode.js/classes/Textmodifier/methods/flipY.md index e88d6818..225efb49 100644 --- a/api/textmode.js/classes/Textmodifier/methods/flipY.md +++ b/api/textmode.js/classes/Textmodifier/methods/flipY.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / flipY diff --git a/api/textmode.js/classes/Textmodifier/methods/floor.md b/api/textmode.js/classes/Textmodifier/methods/floor.md index c0037cea..a728c6bb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/floor.md +++ b/api/textmode.js/classes/Textmodifier/methods/floor.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / floor diff --git a/api/textmode.js/classes/Textmodifier/methods/fontSize.md b/api/textmode.js/classes/Textmodifier/methods/fontSize.md index 7868cca1..632a8a38 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fontSize.md +++ b/api/textmode.js/classes/Textmodifier/methods/fontSize.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / fontSize diff --git a/api/textmode.js/classes/Textmodifier/methods/fract.md b/api/textmode.js/classes/Textmodifier/methods/fract.md index 1eea4c8a..7dfb99ef 100644 --- a/api/textmode.js/classes/Textmodifier/methods/fract.md +++ b/api/textmode.js/classes/Textmodifier/methods/fract.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / fract diff --git a/api/textmode.js/classes/Textmodifier/methods/frameRate.md b/api/textmode.js/classes/Textmodifier/methods/frameRate.md index a447a38f..0b62b3ad 100644 --- a/api/textmode.js/classes/Textmodifier/methods/frameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/frameRate.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / frameRate @@ -32,5 +32,5 @@ Set the target frame rate, or get the current measured frame rate when called wi ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepad.md b/api/textmode.js/classes/Textmodifier/methods/gamepad.md index a84368c2..929c616a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepad.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepad.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepad @@ -15,7 +15,7 @@ lastModified: 2026-07-31 # Method: gamepad() ```ts -gamepad(index): +gamepad(index): | TextmodeGamepadSnapshot | undefined; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md index 66dcf101..eb4da247 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepadAxisChanged diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md index dae1ece1..9cd868ff 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepadButtonPressed diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md index 61340f85..1bb1d08c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepadButtonReleased diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md index d9465031..74eb4849 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepadConnected diff --git a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md index b5039810..fb3aba13 100644 --- a/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md +++ b/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepadDisconnected diff --git a/api/textmode.js/classes/Textmodifier/methods/image.md b/api/textmode.js/classes/Textmodifier/methods/image.md index b28dac43..1ac27ec9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/image.md +++ b/api/textmode.js/classes/Textmodifier/methods/image.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / image @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts image( - source, - width?, + source, + width?, height?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md index e9d0812d..b6e25c8b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/inputGrid.md +++ b/api/textmode.js/classes/Textmodifier/methods/inputGrid.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / inputGrid @@ -40,5 +40,5 @@ When called without arguments, returns the current input grid mode:
## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/invert.md b/api/textmode.js/classes/Textmodifier/methods/invert.md index 82834b33..245a2d55 100644 --- a/api/textmode.js/classes/Textmodifier/methods/invert.md +++ b/api/textmode.js/classes/Textmodifier/methods/invert.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / invert diff --git a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md index 5540a46b..b60ea78a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / isKeyPressed diff --git a/api/textmode.js/classes/Textmodifier/methods/isLooping.md b/api/textmode.js/classes/Textmodifier/methods/isLooping.md index 7584d000..3fe29986 100644 --- a/api/textmode.js/classes/Textmodifier/methods/isLooping.md +++ b/api/textmode.js/classes/Textmodifier/methods/isLooping.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / isLooping @@ -28,5 +28,5 @@ Whether the automatic render loop is currently running. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md index 6d7d838b..f8dea88b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyPressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyPressed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / keyPressed diff --git a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md index 8494a452..e220b30c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyReleased.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / keyReleased diff --git a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md index dfff2b7b..0fdb1b6a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/keyTyped.md +++ b/api/textmode.js/classes/Textmodifier/methods/keyTyped.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / keyTyped diff --git a/api/textmode.js/classes/Textmodifier/methods/lerp.md b/api/textmode.js/classes/Textmodifier/methods/lerp.md index 7809aa9b..696f352d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lerp.md +++ b/api/textmode.js/classes/Textmodifier/methods/lerp.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lerp @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts lerp( - start, - stop, + start, + stop, amount): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md index 44c55f0a..f77cfd40 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md +++ b/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lightFalloff @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts lightFalloff( - constant, - linear, + constant, + linear, quadratic): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/line.md b/api/textmode.js/classes/Textmodifier/methods/line.md index 555121b9..dbc9e718 100644 --- a/api/textmode.js/classes/Textmodifier/methods/line.md +++ b/api/textmode.js/classes/Textmodifier/methods/line.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / line @@ -16,9 +16,9 @@ lastModified: 2026-07-31 ```ts line( - x1, - y1, - x2, + x1, + y1, + x2, y2): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md index d101c55a..14464d0e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lineWeight.md +++ b/api/textmode.js/classes/Textmodifier/methods/lineWeight.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lineWeight diff --git a/api/textmode.js/classes/Textmodifier/methods/loadFont.md b/api/textmode.js/classes/Textmodifier/methods/loadFont.md index 36f7fc7e..cfc8aaae 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadFont.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadFont.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loadFont diff --git a/api/textmode.js/classes/Textmodifier/methods/loadImage.md b/api/textmode.js/classes/Textmodifier/methods/loadImage.md index e61f5293..a895db35 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadImage.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadImage.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loadImage diff --git a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md index 5bf3e163..f73b8637 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadTileset.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadTileset.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loadTileset diff --git a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md index c37064d3..13f59c07 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loadVideo.md +++ b/api/textmode.js/classes/Textmodifier/methods/loadVideo.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loadVideo diff --git a/api/textmode.js/classes/Textmodifier/methods/log.md b/api/textmode.js/classes/Textmodifier/methods/log.md index 8aceb499..7ed3ca26 100644 --- a/api/textmode.js/classes/Textmodifier/methods/log.md +++ b/api/textmode.js/classes/Textmodifier/methods/log.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / log diff --git a/api/textmode.js/classes/Textmodifier/methods/longPress.md b/api/textmode.js/classes/Textmodifier/methods/longPress.md index 7c2b8b6c..652ffe7b 100644 --- a/api/textmode.js/classes/Textmodifier/methods/longPress.md +++ b/api/textmode.js/classes/Textmodifier/methods/longPress.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / longPress diff --git a/api/textmode.js/classes/Textmodifier/methods/lookAt.md b/api/textmode.js/classes/Textmodifier/methods/lookAt.md index 8c5cfcbc..30c8fc02 100644 --- a/api/textmode.js/classes/Textmodifier/methods/lookAt.md +++ b/api/textmode.js/classes/Textmodifier/methods/lookAt.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lookAt @@ -16,11 +16,11 @@ lastModified: 2026-07-31 ```ts lookAt( - targetX, - targetY, - targetZ, - upX?, - upY?, + targetX, + targetY, + targetZ, + upX?, + upY?, upZ?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/loop.md b/api/textmode.js/classes/Textmodifier/methods/loop.md index 7306e74d..e1ec1a59 100644 --- a/api/textmode.js/classes/Textmodifier/methods/loop.md +++ b/api/textmode.js/classes/Textmodifier/methods/loop.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / loop @@ -26,5 +26,5 @@ Resume the rendering loop if it was stopped by [noLoop](noLoop.md). ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/map.md b/api/textmode.js/classes/Textmodifier/methods/map.md index 38136438..30d2c0d4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/map.md +++ b/api/textmode.js/classes/Textmodifier/methods/map.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / map @@ -16,10 +16,10 @@ lastModified: 2026-07-31 ```ts map( - value, - start1, - stop1, - start2, + value, + start1, + stop1, + start2, stop2): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/max.md b/api/textmode.js/classes/Textmodifier/methods/max.md index f1b38436..9407d0d1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/max.md +++ b/api/textmode.js/classes/Textmodifier/methods/max.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / max diff --git a/api/textmode.js/classes/Textmodifier/methods/min.md b/api/textmode.js/classes/Textmodifier/methods/min.md index c31bae0e..f5a49c68 100644 --- a/api/textmode.js/classes/Textmodifier/methods/min.md +++ b/api/textmode.js/classes/Textmodifier/methods/min.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / min diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md index 05bb98ff..7d7ba5a1 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseClicked diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md index ec234e6d..9a5ad319 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseDragged diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md index 44b5d452..2f252697 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseMoved diff --git a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md index c3f50f87..00dd5538 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mousePressed.md +++ b/api/textmode.js/classes/Textmodifier/methods/mousePressed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mousePressed diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md index a41a79eb..a249c241 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseReleased diff --git a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md index aaef85bd..d13d150d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md +++ b/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseScrolled diff --git a/api/textmode.js/classes/Textmodifier/methods/noLights.md b/api/textmode.js/classes/Textmodifier/methods/noLights.md index c6b935b4..653366ee 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLights.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLights.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noLights diff --git a/api/textmode.js/classes/Textmodifier/methods/noLoop.md b/api/textmode.js/classes/Textmodifier/methods/noLoop.md index 876feffd..393ffd03 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noLoop.md +++ b/api/textmode.js/classes/Textmodifier/methods/noLoop.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noLoop @@ -28,5 +28,5 @@ Rendering can be resumed later with [loop](loop.md). ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/noTexture.md b/api/textmode.js/classes/Textmodifier/methods/noTexture.md index 630e394b..3b8a15ec 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noTexture.md +++ b/api/textmode.js/classes/Textmodifier/methods/noTexture.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noTexture diff --git a/api/textmode.js/classes/Textmodifier/methods/noise.md b/api/textmode.js/classes/Textmodifier/methods/noise.md index 4db20f4a..a438f9f9 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noise.md +++ b/api/textmode.js/classes/Textmodifier/methods/noise.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noise @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts noise( - x, - y?, + x, + y?, z?): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md index 92daf013..92e3c891 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noiseDetail diff --git a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md index c1ce4575..6312bada 100644 --- a/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / noiseSeed diff --git a/api/textmode.js/classes/Textmodifier/methods/norm.md b/api/textmode.js/classes/Textmodifier/methods/norm.md index 81217f9e..75693b55 100644 --- a/api/textmode.js/classes/Textmodifier/methods/norm.md +++ b/api/textmode.js/classes/Textmodifier/methods/norm.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / norm @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts norm( - value, - start, + value, + start, stop): number; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/off.md b/api/textmode.js/classes/Textmodifier/methods/off.md index 6c65e93d..35cb8097 100644 --- a/api/textmode.js/classes/Textmodifier/methods/off.md +++ b/api/textmode.js/classes/Textmodifier/methods/off.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / off diff --git a/api/textmode.js/classes/Textmodifier/methods/on.md b/api/textmode.js/classes/Textmodifier/methods/on.md index 4aefbdbd..c8e074f4 100644 --- a/api/textmode.js/classes/Textmodifier/methods/on.md +++ b/api/textmode.js/classes/Textmodifier/methods/on.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / on diff --git a/api/textmode.js/classes/Textmodifier/methods/once.md b/api/textmode.js/classes/Textmodifier/methods/once.md index 31274ea2..e5d9e377 100644 --- a/api/textmode.js/classes/Textmodifier/methods/once.md +++ b/api/textmode.js/classes/Textmodifier/methods/once.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / once diff --git a/api/textmode.js/classes/Textmodifier/methods/ortho.md b/api/textmode.js/classes/Textmodifier/methods/ortho.md index 28a4fbe6..165c1fbf 100644 --- a/api/textmode.js/classes/Textmodifier/methods/ortho.md +++ b/api/textmode.js/classes/Textmodifier/methods/ortho.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / ortho diff --git a/api/textmode.js/classes/Textmodifier/methods/perspective.md b/api/textmode.js/classes/Textmodifier/methods/perspective.md index fad2d1c6..f65d67c0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/perspective.md +++ b/api/textmode.js/classes/Textmodifier/methods/perspective.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / perspective @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts perspective( - fov?, - near?, + fov?, + near?, far?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pinch.md b/api/textmode.js/classes/Textmodifier/methods/pinch.md index 05f83004..213ccd57 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pinch.md +++ b/api/textmode.js/classes/Textmodifier/methods/pinch.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pinch diff --git a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md index 92d6371d..1deb3669 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md +++ b/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pixelDensity @@ -30,7 +30,7 @@ Current pixel density. ### Example - + ## Call Signature @@ -54,5 +54,5 @@ This resizes the canvas backing store while keeping the CSS display size unchang ### Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/point.md b/api/textmode.js/classes/Textmodifier/methods/point.md index 7e60ace6..eec35efa 100644 --- a/api/textmode.js/classes/Textmodifier/methods/point.md +++ b/api/textmode.js/classes/Textmodifier/methods/point.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / point diff --git a/api/textmode.js/classes/Textmodifier/methods/pointLight.md b/api/textmode.js/classes/Textmodifier/methods/pointLight.md index 9ba2c979..24e227fd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pointLight.md +++ b/api/textmode.js/classes/Textmodifier/methods/pointLight.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pointLight @@ -18,11 +18,11 @@ lastModified: 2026-07-31 ```ts pointLight( - v1, - v2, - v3, - x, - y, + v1, + v2, + v3, + x, + y, z): void; ``` @@ -54,9 +54,9 @@ Up to five point lights are supported per frame. Additional calls are ignored. ```ts pointLight( - v1, - v2, - v3, + v1, + v2, + v3, position): void; ``` @@ -83,9 +83,9 @@ Add a point light using RGB components and an object position. ```ts pointLight( - color, - x, - y, + color, + x, + y, z): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/pop.md b/api/textmode.js/classes/Textmodifier/methods/pop.md index f502393b..51d5e343 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pop.md +++ b/api/textmode.js/classes/Textmodifier/methods/pop.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pop diff --git a/api/textmode.js/classes/Textmodifier/methods/postDraw.md b/api/textmode.js/classes/Textmodifier/methods/postDraw.md index fa79fd25..4984f493 100644 --- a/api/textmode.js/classes/Textmodifier/methods/postDraw.md +++ b/api/textmode.js/classes/Textmodifier/methods/postDraw.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / postDraw diff --git a/api/textmode.js/classes/Textmodifier/methods/pow.md b/api/textmode.js/classes/Textmodifier/methods/pow.md index c54cf5fb..50818310 100644 --- a/api/textmode.js/classes/Textmodifier/methods/pow.md +++ b/api/textmode.js/classes/Textmodifier/methods/pow.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pow diff --git a/api/textmode.js/classes/Textmodifier/methods/print.md b/api/textmode.js/classes/Textmodifier/methods/print.md index abf6df43..01a413c8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/print.md +++ b/api/textmode.js/classes/Textmodifier/methods/print.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / print @@ -16,9 +16,9 @@ lastModified: 2026-07-31 ```ts print( - str, - x, - y, + str, + x, + y, options?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/printAlign.md b/api/textmode.js/classes/Textmodifier/methods/printAlign.md index 46a7c0b1..4c543663 100644 --- a/api/textmode.js/classes/Textmodifier/methods/printAlign.md +++ b/api/textmode.js/classes/Textmodifier/methods/printAlign.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / printAlign diff --git a/api/textmode.js/classes/Textmodifier/methods/push.md b/api/textmode.js/classes/Textmodifier/methods/push.md index 19bbf2af..b2743b0c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/push.md +++ b/api/textmode.js/classes/Textmodifier/methods/push.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / push diff --git a/api/textmode.js/classes/Textmodifier/methods/radians.md b/api/textmode.js/classes/Textmodifier/methods/radians.md index d769dd6c..0dedf1e0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/radians.md +++ b/api/textmode.js/classes/Textmodifier/methods/radians.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / radians diff --git a/api/textmode.js/classes/Textmodifier/methods/random.md b/api/textmode.js/classes/Textmodifier/methods/random.md index 753ee3f0..6847fbb6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/random.md +++ b/api/textmode.js/classes/Textmodifier/methods/random.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / random diff --git a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md index c4d7c6b2..e8022295 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / randomGaussian diff --git a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md index 2f3068d6..ae0896bc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomSeed.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomSeed.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / randomSeed diff --git a/api/textmode.js/classes/Textmodifier/methods/randomStream.md b/api/textmode.js/classes/Textmodifier/methods/randomStream.md index 07d45910..2ff26887 100644 --- a/api/textmode.js/classes/Textmodifier/methods/randomStream.md +++ b/api/textmode.js/classes/Textmodifier/methods/randomStream.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / randomStream diff --git a/api/textmode.js/classes/Textmodifier/methods/rect.md b/api/textmode.js/classes/Textmodifier/methods/rect.md index 0508fdec..3f3cce3e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rect.md +++ b/api/textmode.js/classes/Textmodifier/methods/rect.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rect diff --git a/api/textmode.js/classes/Textmodifier/methods/redraw.md b/api/textmode.js/classes/Textmodifier/methods/redraw.md index 0f1fb4b9..0e99eba8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/redraw.md +++ b/api/textmode.js/classes/Textmodifier/methods/redraw.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / redraw @@ -35,5 +35,5 @@ allowing you to trigger rendering on demand. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md index 65a03198..db56fa71 100644 --- a/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md +++ b/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / requestPointerLock diff --git a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md index d4cb7ddf..dd691964 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetCamera.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / resetCamera diff --git a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md index 9357366f..4def02dc 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / resetMatrix diff --git a/api/textmode.js/classes/Textmodifier/methods/resetShader.md b/api/textmode.js/classes/Textmodifier/methods/resetShader.md index 1afd5768..b5d4deb8 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resetShader.md +++ b/api/textmode.js/classes/Textmodifier/methods/resetShader.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / resetShader diff --git a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md index 35e721cf..00fdfb91 100644 --- a/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md +++ b/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / resizeCanvas @@ -33,5 +33,5 @@ Resize the canvas and adjust all related components accordingly. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/rotate.md b/api/textmode.js/classes/Textmodifier/methods/rotate.md index 3e016ae2..932a30c0 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotate.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotate.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rotate @@ -69,8 +69,8 @@ rotate(angle, axis): void; ```ts rotate( - degreesX?, - degreesY?, + degreesX?, + degreesY?, degreesZ?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md index 91ba4265..70c9636c 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rotateGesture diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateX.md b/api/textmode.js/classes/Textmodifier/methods/rotateX.md index b6911c70..70984b75 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateX.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rotateX diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateY.md b/api/textmode.js/classes/Textmodifier/methods/rotateY.md index 84a59c55..1fde7cc3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateY.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rotateY diff --git a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md index ff62b38e..bf7b5e37 100644 --- a/api/textmode.js/classes/Textmodifier/methods/rotateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/rotateZ.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / rotateZ diff --git a/api/textmode.js/classes/Textmodifier/methods/round.md b/api/textmode.js/classes/Textmodifier/methods/round.md index 03c41731..be49a6da 100644 --- a/api/textmode.js/classes/Textmodifier/methods/round.md +++ b/api/textmode.js/classes/Textmodifier/methods/round.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / round diff --git a/api/textmode.js/classes/Textmodifier/methods/scale.md b/api/textmode.js/classes/Textmodifier/methods/scale.md index 1ffb5029..85e849fb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/scale.md +++ b/api/textmode.js/classes/Textmodifier/methods/scale.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / scale @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts scale( - x, - y?, + x, + y?, z?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/setCamera.md b/api/textmode.js/classes/Textmodifier/methods/setCamera.md index d6c07d38..c9bb6b3e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setCamera.md +++ b/api/textmode.js/classes/Textmodifier/methods/setCamera.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / setCamera diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniform.md b/api/textmode.js/classes/Textmodifier/methods/setUniform.md index b0da768e..f7ab68ea 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniform.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniform.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / setUniform diff --git a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md index aa73a944..c3e3f1eb 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setUniforms.md +++ b/api/textmode.js/classes/Textmodifier/methods/setUniforms.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / setUniforms diff --git a/api/textmode.js/classes/Textmodifier/methods/setup.md b/api/textmode.js/classes/Textmodifier/methods/setup.md index f48e4f7f..8531f723 100644 --- a/api/textmode.js/classes/Textmodifier/methods/setup.md +++ b/api/textmode.js/classes/Textmodifier/methods/setup.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / setup @@ -37,5 +37,5 @@ The callback can be asynchronous (return a Promise). ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/shader.md b/api/textmode.js/classes/Textmodifier/methods/shader.md index 2a9807ec..6e29ec21 100644 --- a/api/textmode.js/classes/Textmodifier/methods/shader.md +++ b/api/textmode.js/classes/Textmodifier/methods/shader.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / shader diff --git a/api/textmode.js/classes/Textmodifier/methods/sin.md b/api/textmode.js/classes/Textmodifier/methods/sin.md index 211d8934..eeae35a6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sin.md +++ b/api/textmode.js/classes/Textmodifier/methods/sin.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / sin diff --git a/api/textmode.js/classes/Textmodifier/methods/sphere.md b/api/textmode.js/classes/Textmodifier/methods/sphere.md index 4525d984..eebeda37 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sphere.md +++ b/api/textmode.js/classes/Textmodifier/methods/sphere.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / sphere diff --git a/api/textmode.js/classes/Textmodifier/methods/sq.md b/api/textmode.js/classes/Textmodifier/methods/sq.md index 191c948f..e93c6a02 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sq.md +++ b/api/textmode.js/classes/Textmodifier/methods/sq.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / sq diff --git a/api/textmode.js/classes/Textmodifier/methods/sqrt.md b/api/textmode.js/classes/Textmodifier/methods/sqrt.md index 3db18219..e9614263 100644 --- a/api/textmode.js/classes/Textmodifier/methods/sqrt.md +++ b/api/textmode.js/classes/Textmodifier/methods/sqrt.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / sqrt diff --git a/api/textmode.js/classes/Textmodifier/methods/stroke.md b/api/textmode.js/classes/Textmodifier/methods/stroke.md index 0fef519f..7ee3f36e 100644 --- a/api/textmode.js/classes/Textmodifier/methods/stroke.md +++ b/api/textmode.js/classes/Textmodifier/methods/stroke.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / stroke @@ -59,9 +59,9 @@ Alias for [charColor](charColor.md). Set the stroke (character) color using a gr ```ts stroke( - r, - g, - b, + r, + g, + b, a?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/swipe.md b/api/textmode.js/classes/Textmodifier/methods/swipe.md index a86e75af..45307b31 100644 --- a/api/textmode.js/classes/Textmodifier/methods/swipe.md +++ b/api/textmode.js/classes/Textmodifier/methods/swipe.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / swipe diff --git a/api/textmode.js/classes/Textmodifier/methods/tan.md b/api/textmode.js/classes/Textmodifier/methods/tan.md index 1b34d46c..a836e366 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tan.md +++ b/api/textmode.js/classes/Textmodifier/methods/tan.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / tan diff --git a/api/textmode.js/classes/Textmodifier/methods/tap.md b/api/textmode.js/classes/Textmodifier/methods/tap.md index 1ec1ef22..2b829e03 100644 --- a/api/textmode.js/classes/Textmodifier/methods/tap.md +++ b/api/textmode.js/classes/Textmodifier/methods/tap.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / tap diff --git a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md index c612632c..a2a5a59d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md +++ b/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / targetFrameRate @@ -36,5 +36,5 @@ Current target frame rate when called without arguments. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/methods/texture.md b/api/textmode.js/classes/Textmodifier/methods/texture.md index 12c3d948..f1ef593f 100644 --- a/api/textmode.js/classes/Textmodifier/methods/texture.md +++ b/api/textmode.js/classes/Textmodifier/methods/texture.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / texture diff --git a/api/textmode.js/classes/Textmodifier/methods/torus.md b/api/textmode.js/classes/Textmodifier/methods/torus.md index 8c9e718d..b2aa4478 100644 --- a/api/textmode.js/classes/Textmodifier/methods/torus.md +++ b/api/textmode.js/classes/Textmodifier/methods/torus.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / torus diff --git a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md index 5c9d7a3a..b18bef73 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / touchCancelled diff --git a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md index cad28248..17969873 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchEnded.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchEnded.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / touchEnded diff --git a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md index 5454552b..27262ffd 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchMoved.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchMoved.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / touchMoved diff --git a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md index 618393e5..9acb1c1a 100644 --- a/api/textmode.js/classes/Textmodifier/methods/touchStarted.md +++ b/api/textmode.js/classes/Textmodifier/methods/touchStarted.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / touchStarted diff --git a/api/textmode.js/classes/Textmodifier/methods/translate.md b/api/textmode.js/classes/Textmodifier/methods/translate.md index d50b9546..8ec309db 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translate.md +++ b/api/textmode.js/classes/Textmodifier/methods/translate.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / translate @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts translate( - x?, - y?, + x?, + y?, z?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/translateX.md b/api/textmode.js/classes/Textmodifier/methods/translateX.md index 8345d6c5..fd913731 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateX.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateX.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / translateX diff --git a/api/textmode.js/classes/Textmodifier/methods/translateY.md b/api/textmode.js/classes/Textmodifier/methods/translateY.md index 4110f87f..cdd663f6 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateY.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateY.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / translateY diff --git a/api/textmode.js/classes/Textmodifier/methods/translateZ.md b/api/textmode.js/classes/Textmodifier/methods/translateZ.md index fef25392..e678e4de 100644 --- a/api/textmode.js/classes/Textmodifier/methods/translateZ.md +++ b/api/textmode.js/classes/Textmodifier/methods/translateZ.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / translateZ diff --git a/api/textmode.js/classes/Textmodifier/methods/triangle.md b/api/textmode.js/classes/Textmodifier/methods/triangle.md index b1951069..ab970b14 100644 --- a/api/textmode.js/classes/Textmodifier/methods/triangle.md +++ b/api/textmode.js/classes/Textmodifier/methods/triangle.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / triangle @@ -16,11 +16,11 @@ lastModified: 2026-07-31 ```ts triangle( - x1, - y1, - x2, - y2, - x3, + x1, + y1, + x2, + y2, + x3, y3): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md index e870dbef..61e510c3 100644 --- a/api/textmode.js/classes/Textmodifier/methods/useTileColors.md +++ b/api/textmode.js/classes/Textmodifier/methods/useTileColors.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / useTileColors diff --git a/api/textmode.js/classes/Textmodifier/methods/vertex.md b/api/textmode.js/classes/Textmodifier/methods/vertex.md index f45c9af3..7bacc423 100644 --- a/api/textmode.js/classes/Textmodifier/methods/vertex.md +++ b/api/textmode.js/classes/Textmodifier/methods/vertex.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / vertex @@ -16,8 +16,8 @@ lastModified: 2026-07-31 ```ts vertex( - x, - y, + x, + y, z?): void; ``` diff --git a/api/textmode.js/classes/Textmodifier/methods/windowResized.md b/api/textmode.js/classes/Textmodifier/methods/windowResized.md index 97ca9bd3..bb76fe4d 100644 --- a/api/textmode.js/classes/Textmodifier/methods/windowResized.md +++ b/api/textmode.js/classes/Textmodifier/methods/windowResized.md @@ -7,7 +7,7 @@ category: Methods api: true owner: Textmodifier kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / windowResized @@ -32,5 +32,5 @@ Set the callback that runs after a window resize. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md index c39110f4..77f66ef0 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_ADDITIVE diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md index be235293..51281df0 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_COLOR\_BURN diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md index 737b9037..0b6777a9 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_COLOR\_DODGE diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md index 0c637627..9f928608 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_DARKEN diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md index ec4904fb..230af1b2 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_DIFFERENCE diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md index 2201ece3..a2423a02 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_EXCLUSION diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md index a8692632..427cdbb0 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_HARD\_LIGHT diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md index 795681db..7039b603 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_LIGHTEN diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md index 9414abe9..b8a93255 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_MULTIPLY diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md index b548338c..41260a4e 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_NORMAL diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md index 7226d4e3..3f3f43f7 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_OVERLAY diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md index 93d01621..b998c338 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_SCREEN diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md index b6f9af80..a2581a63 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_SOFT\_LIGHT diff --git a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md index 337906a9..d3e6d09d 100644 --- a/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md +++ b/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / BLEND\_SUBTRACT diff --git a/api/textmode.js/classes/Textmodifier/properties/LINES.md b/api/textmode.js/classes/Textmodifier/properties/LINES.md index c163e2ee..55ba7486 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINES.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINES.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / LINES diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md index 1fd4ee7b..1eeb4732 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / LINE\_LOOP diff --git a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md index ad6a314b..1eca203f 100644 --- a/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / LINE\_STRIP diff --git a/api/textmode.js/classes/Textmodifier/properties/POINTS.md b/api/textmode.js/classes/Textmodifier/properties/POINTS.md index 251258db..e986425a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/POINTS.md +++ b/api/textmode.js/classes/Textmodifier/properties/POINTS.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / POINTS diff --git a/api/textmode.js/classes/Textmodifier/properties/QUADS.md b/api/textmode.js/classes/Textmodifier/properties/QUADS.md index db89bd9c..7d920eeb 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUADS.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUADS.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / QUADS diff --git a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md index 15e6aa9f..64592546 100644 --- a/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / QUAD\_STRIP diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md index 1c301f72..53c9a89f 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / TRIANGLES diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md index 07e89a30..8c11e34e 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / TRIANGLE\_FAN diff --git a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md index 323b3d81..22aac110 100644 --- a/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md +++ b/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / TRIANGLE\_STRIP diff --git a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md index 1fe996fa..1d858cf0 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayHeight.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / displayHeight @@ -22,5 +22,5 @@ Physical screen height in pixels. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md index 5116f67e..31331fff 100644 --- a/api/textmode.js/classes/Textmodifier/properties/displayWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/displayWidth.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / displayWidth @@ -22,5 +22,5 @@ Physical screen width in pixels. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/properties/gamepads.md b/api/textmode.js/classes/Textmodifier/properties/gamepads.md index 179f48de..362248a4 100644 --- a/api/textmode.js/classes/Textmodifier/properties/gamepads.md +++ b/api/textmode.js/classes/Textmodifier/properties/gamepads.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / gamepads diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md index 710f1dc7..f2acd317 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lastKeyPressed diff --git a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md index de56d2a8..cd56410c 100644 --- a/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md +++ b/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / lastKeyReleased diff --git a/api/textmode.js/classes/Textmodifier/properties/modifierState.md b/api/textmode.js/classes/Textmodifier/properties/modifierState.md index 914fda52..2696afb4 100644 --- a/api/textmode.js/classes/Textmodifier/properties/modifierState.md +++ b/api/textmode.js/classes/Textmodifier/properties/modifierState.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / modifierState diff --git a/api/textmode.js/classes/Textmodifier/properties/mouse.md b/api/textmode.js/classes/Textmodifier/properties/mouse.md index 1399712f..88cf9a97 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouse.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouse diff --git a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md index 74fe60c4..8c16a624 100644 --- a/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md +++ b/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / mouseIsPressed diff --git a/api/textmode.js/classes/Textmodifier/properties/movedX.md b/api/textmode.js/classes/Textmodifier/properties/movedX.md index e0822d32..45ce71fa 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedX.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedX.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / movedX diff --git a/api/textmode.js/classes/Textmodifier/properties/movedY.md b/api/textmode.js/classes/Textmodifier/properties/movedY.md index 8dea57cd..392b63e7 100644 --- a/api/textmode.js/classes/Textmodifier/properties/movedY.md +++ b/api/textmode.js/classes/Textmodifier/properties/movedY.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / movedY diff --git a/api/textmode.js/classes/Textmodifier/properties/pmouse.md b/api/textmode.js/classes/Textmodifier/properties/pmouse.md index d1691008..5050758b 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pmouse.md +++ b/api/textmode.js/classes/Textmodifier/properties/pmouse.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pmouse diff --git a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md index 94ccb1f9..4ce8f4bd 100644 --- a/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md +++ b/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / pressedKeys diff --git a/api/textmode.js/classes/Textmodifier/properties/touches.md b/api/textmode.js/classes/Textmodifier/properties/touches.md index 9d76be67..c7aadd1a 100644 --- a/api/textmode.js/classes/Textmodifier/properties/touches.md +++ b/api/textmode.js/classes/Textmodifier/properties/touches.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / touches diff --git a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md index 517c07b3..733e1866 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowHeight.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowHeight.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / windowHeight @@ -22,5 +22,5 @@ Current browser window height in pixels. ## Example - + diff --git a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md index 104a0e21..8fb0c2cd 100644 --- a/api/textmode.js/classes/Textmodifier/properties/windowWidth.md +++ b/api/textmode.js/classes/Textmodifier/properties/windowWidth.md @@ -7,7 +7,7 @@ category: Properties api: true owner: Textmodifier kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [Textmodifier](../../Textmodifier.md) / windowWidth @@ -22,5 +22,5 @@ Current browser window width in pixels. ## Example - + diff --git a/api/textmode.js/classes/textmode.md b/api/textmode.js/classes/textmode.md index c5ee05f0..043eb04d 100644 --- a/api/textmode.js/classes/textmode.md +++ b/api/textmode.js/classes/textmode.md @@ -6,7 +6,7 @@ description: The main entry point for the textmode.js library. category: Classes api: true kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/classes/textmode/accessors/version.md b/api/textmode.js/classes/textmode/accessors/version.md index 9e610741..bab1013b 100644 --- a/api/textmode.js/classes/textmode/accessors/version.md +++ b/api/textmode.js/classes/textmode/accessors/version.md @@ -7,7 +7,7 @@ category: Accessors api: true owner: textmode kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [textmode](../../textmode.md) / version diff --git a/api/textmode.js/classes/textmode/methods/create.md b/api/textmode.js/classes/textmode/methods/create.md index b8db4823..0a284000 100644 --- a/api/textmode.js/classes/textmode/methods/create.md +++ b/api/textmode.js/classes/textmode/methods/create.md @@ -7,7 +7,7 @@ category: Methods api: true owner: textmode kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [textmode](../../textmode.md) / create diff --git a/api/textmode.js/classes/textmode/methods/setErrorLevel.md b/api/textmode.js/classes/textmode/methods/setErrorLevel.md index aaf24a3c..dbdcadd0 100644 --- a/api/textmode.js/classes/textmode/methods/setErrorLevel.md +++ b/api/textmode.js/classes/textmode/methods/setErrorLevel.md @@ -7,7 +7,7 @@ category: Methods api: true owner: textmode kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [textmode](../../textmode.md) / setErrorLevel diff --git a/api/textmode.js/enumerations/ShapeAssemblyMode.md b/api/textmode.js/enumerations/ShapeAssemblyMode.md index 97b105b9..36dcf52b 100644 --- a/api/textmode.js/enumerations/ShapeAssemblyMode.md +++ b/api/textmode.js/enumerations/ShapeAssemblyMode.md @@ -6,7 +6,7 @@ description: Shape assembly modes for Textmodifier.beginShape. category: Enumerations api: true kind: Enum -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../index.md) / ShapeAssemblyMode diff --git a/api/textmode.js/index.md b/api/textmode.js/index.md index bc3831c8..a16f6491 100644 --- a/api/textmode.js/index.md +++ b/api/textmode.js/index.md @@ -6,51 +6,136 @@ description: textmode.js is a lightweight creative coding library for creating r category: API Reference api: true kind: Project -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- # textmode.js -~ travelling without arriving +Build real-time ASCII and textmode graphics in the browser with a grid-based +WebGL2 drawing interface. Create a [textmode](classes/textmode.md) drawing context, then +compose characters, colors, shapes, media, layers, and effects on its grid. -## Namespaces +## Start a sketch + +```javascript +const t = textmode.create({ + width: window.innerWidth, + height: window.innerHeight, + fontSize: 16 +}); + +t.draw(() => { + t.background(8); + t.char('@'); + t.charColor(255, 180, 80); + t.point(); +}); + +t.windowResized(() => { + t.resizeCanvas(window.innerWidth, window.innerHeight); +}); +``` + +## Sketch workflow + +1. Create the drawing context with [textmode.create](classes/textmode/methods/create.md). +2. Load or configure resources in [Textmodifier.setup](classes/Textmodifier/methods/setup.md). +3. Draw the base scene in [Textmodifier.draw](classes/Textmodifier/methods/draw.md). +4. Add layers, media conversion, filters, or shaders when the sketch needs them. +5. Respond to resize and input events as the sketch runs. + +Read the [first sketch guide](/docs/first-sketch), +[fundamentals](/docs/fundamentals), and [examples](/docs/examples) for +guided learning; use [Textmodifier](classes/Textmodifier.md) for the complete drawing interface. + +## Conversion & filters + +Convert visual sources into textmode data and post-process the result. | Namespace | Description | | ------ | ------ | -| [color](namespaces/color/index.md) | Color objects, color modes, and types. | | [conversion](namespaces/conversion/index.md) | All media conversion related modules and types. | -| [errors](namespaces/errors/index.md) | All error handling related modules and types. | | [filters](namespaces/filters/index.md) | All filter related modules and types. | -| [fonts](namespaces/fonts/index.md) | All font rendering related modules and types. | -| [input](namespaces/input/index.md) | All types and interfaces related to input event handling. | -| [layering](namespaces/layering/index.md) | All modules and types related to multi-layered textmode rendering. | -| [loading](namespaces/loading/index.md) | All loading screen related modules and types. | -| [media](namespaces/media/index.md) | All media asset related modules and types. | -| [plugins](namespaces/plugins/index.md) | Plugin system types for extending textmode.js functionality. | -## Enumerations +## Core workflow -| Enumeration | Description | +Create, configure, and run a textmode sketch. + +| Name | Description | | ------ | ------ | -| [ShapeAssemblyMode](enumerations/ShapeAssemblyMode.md) | Shape assembly modes for [Textmodifier.beginShape](classes/Textmodifier/methods/beginShape.md). | +| [textmode](classes/textmode.md) | The main entry point for the `textmode.js` library. | +| [Textmodifier](classes/Textmodifier.md) | The main `textmode.js` drawing context. | +| [TextmodeOptions](type-aliases/TextmodeOptions.md) | Options when creating a [Textmodifier](classes/Textmodifier.md) instance via [textmode.create](classes/textmode/methods/create.md). | -## Classes +## Creative coding utilities + +Use deterministic randomness and vector math in generative sketches. | Class | Description | | ------ | ------ | -| [textmode](classes/textmode.md) | The main entry point for the `textmode.js` library. | +| [TextmodeRandom](classes/TextmodeRandom.md) | A deterministic pseudo-random number generator for textmode sketches. | +| [TextmodeVector](classes/TextmodeVector.md) | Mutable two- or three-dimensional vector for creative-coding math. | + +## Drawing & 3D + +Draw primitives and control the camera used for spatial scenes. + +| Name | Description | +| ------ | ------ | +| [ShapeAssemblyMode](enumerations/ShapeAssemblyMode.md) | Shape assembly modes for [Textmodifier.beginShape](classes/Textmodifier/methods/beginShape.md). | | [TextmodeCamera](classes/TextmodeCamera.md) | Mutable camera object used for p5-style camera workflows. | -| [TextmodeFramebuffer](classes/TextmodeFramebuffer.md) | Framebuffer class for managing offscreen rendering targets initialized via [Textmodifier.createFramebuffer](classes/Textmodifier/methods/createFramebuffer.md). | + +## Fonts & media + +Load glyph sources and use images, video, and live textures. + +| Namespace | Description | +| ------ | ------ | +| [fonts](namespaces/fonts/index.md) | All font rendering related modules and types. | +| [media](namespaces/media/index.md) | All media asset related modules and types. | + +## Grid, glyphs & color + +Define the cell-based visual language of a sketch. + +| Name | Description | +| ------ | ------ | +| [color](namespaces/color/index.md) | Color objects, color modes, and types. | | [TextmodeGlyphRamp](classes/TextmodeGlyphRamp.md) | Immutable character sequence for mapping numbers to glyphs. | | [TextmodeGrid](classes/TextmodeGrid.md) | Grid used by a textmode layer. | -| [TextmodeRandom](classes/TextmodeRandom.md) | A deterministic pseudo-random number generator for textmode sketches. | -| [TextmodeShader](classes/TextmodeShader.md) | WebGL shader program created by [Textmodifier.createMaterialShader](classes/Textmodifier/methods/createMaterialShader.md), [Textmodifier.createFilterShader](classes/Textmodifier/methods/createFilterShader.md), or [Textmodifier.createShader](classes/Textmodifier/methods/createShader.md). | -| [TextmodeVector](classes/TextmodeVector.md) | Mutable two- or three-dimensional vector for creative-coding math. | -| [Textmodifier](classes/Textmodifier.md) | The main `textmode.js` drawing context. | -## Type Aliases +## Interaction + +Respond to keyboard, mouse, touch, and gamepad input. + +| Namespace | Description | +| ------ | ------ | +| [input](namespaces/input/index.md) | All types and interfaces related to input event handling. | + +## Layers & GPU rendering -| Type Alias | Description | +Compose scenes and work with GPU-backed drawing resources. + +| Name | Description | | ------ | ------ | +| [layering](namespaces/layering/index.md) | All modules and types related to multi-layered textmode rendering. | +| [TextmodeFramebuffer](classes/TextmodeFramebuffer.md) | Framebuffer class for managing offscreen rendering targets initialized via [Textmodifier.createFramebuffer](classes/Textmodifier/methods/createFramebuffer.md). | +| [TextmodeShader](classes/TextmodeShader.md) | WebGL shader program created by [Textmodifier.createMaterialShader](classes/Textmodifier/methods/createMaterialShader.md) or [Textmodifier.createShader](classes/Textmodifier/methods/createShader.md). | | [TextmodeFramebufferOptions](type-aliases/TextmodeFramebufferOptions.md) | Options for creating a framebuffer via [Textmodifier.createFramebuffer](classes/Textmodifier/methods/createFramebuffer.md). If not specified, width and height default to the current textmode grid size. | -| [TextmodeOptions](type-aliases/TextmodeOptions.md) | Options when creating a [Textmodifier](classes/Textmodifier.md) instance via [textmode.create](classes/textmode/methods/create.md). | + +## Loading & errors + +Control loading feedback and diagnose runtime failures. + +| Namespace | Description | +| ------ | ------ | +| [errors](namespaces/errors/index.md) | All error handling related modules and types. | +| [loading](namespaces/loading/index.md) | All loading screen related modules and types. | + +## Plugins + +Extend layers, sources, and the sketch lifecycle. + +| Namespace | Description | +| ------ | ------ | +| [plugins](namespaces/plugins/index.md) | Plugin system types for extending textmode.js functionality. | diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor.md b/api/textmode.js/namespaces/color/classes/TextmodeColor.md index 62fd21b7..797f9a62 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: color kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md index 3c2d905f..011ecb2e 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / normalized diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md index 18f1e940..6d49790e 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / rgb diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md index 25f34379..cd3fbbcc 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / rgba diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md index 31be15c5..f5cde4b9 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / withAlpha diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md index c9bff067..016269b7 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / a diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md index 1a47b901..6164ec63 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / b diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md index 4b22bebc..2d2f025c 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / g diff --git a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md index accb3b1f..4f345763 100644 --- a/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md +++ b/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md @@ -8,7 +8,7 @@ api: true owner: TextmodeColor namespace: color kind: Property -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [color](../../../index.md) / [TextmodeColor](../../TextmodeColor.md) / r diff --git a/api/textmode.js/namespaces/color/index.md b/api/textmode.js/namespaces/color/index.md index ec933332..b70fd5ec 100644 --- a/api/textmode.js/namespaces/color/index.md +++ b/api/textmode.js/namespaces/color/index.md @@ -6,7 +6,7 @@ description: Color objects, color modes, and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / color diff --git a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md index 3caaaa66..b036befe 100644 --- a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md +++ b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: color kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [color](../index.md) / TextmodeColorMode diff --git a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md index 651f5449..44af5cd5 100644 --- a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md +++ b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: color kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [color](../index.md) / TextmodeColorModeState diff --git a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md index 71ae5749..ef03756d 100644 --- a/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md +++ b/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: color kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [color](../index.md) / TextmodeColorTuple @@ -15,7 +15,7 @@ lastModified: 2026-07-31 # Type Alias: TextmodeColorTuple ```ts -type TextmodeColorTuple = +type TextmodeColorTuple = | [number, number, number] | [number, number, number, number]; ``` diff --git a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md index c408ad66..5e5efb23 100644 --- a/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md +++ b/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: conversion kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/conversion/index.md b/api/textmode.js/namespaces/conversion/index.md index f8bd2959..671721e5 100644 --- a/api/textmode.js/namespaces/conversion/index.md +++ b/api/textmode.js/namespaces/conversion/index.md @@ -6,7 +6,7 @@ description: All media conversion related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / conversion diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md index 5c1c09ae..2331ac07 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: conversion kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md index c27abc93..39aa0c61 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: conversion kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md index 343a7977..5ea87a69 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: conversion kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md index ddf96d15..9385f874 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: conversion kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md index 87e4ef4b..b0315cf7 100644 --- a/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md +++ b/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: conversion kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md b/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md index f2ab355e..f6ca5088 100644 --- a/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md +++ b/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: conversion kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [conversion](../index.md) / BuiltInConversionMode diff --git a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md index 97434445..f0787ec5 100644 --- a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md +++ b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: conversion kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [conversion](../index.md) / TextmodeColorInput @@ -15,7 +15,7 @@ lastModified: 2026-07-31 # Type Alias: TextmodeColorInput ```ts -type TextmodeColorInput = +type TextmodeColorInput = | number | string | TextmodeColor diff --git a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md index 43124e1d..a35ebe11 100644 --- a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md +++ b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: conversion kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [conversion](../index.md) / TextmodeConversionMode diff --git a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md index 327d53bb..a020d2b3 100644 --- a/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md +++ b/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: conversion kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [conversion](../index.md) / TextmodeConversionStepOptions diff --git a/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md b/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md index c2f4836e..0e8652a0 100644 --- a/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md +++ b/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: errors kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: true --- diff --git a/api/textmode.js/namespaces/errors/classes/TextmodeError.md b/api/textmode.js/namespaces/errors/classes/TextmodeError.md index af5ebb5d..e57f4a07 100644 --- a/api/textmode.js/namespaces/errors/classes/TextmodeError.md +++ b/api/textmode.js/namespaces/errors/classes/TextmodeError.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: errors kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: true --- @@ -28,8 +28,8 @@ Error type that formats optional context data alongside the main message. ```ts new TextmodeError( - message, - context?, + message, + context?, options?): TextmodeError; ``` diff --git a/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md b/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md index 06f2ee7c..e59a1676 100644 --- a/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md +++ b/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md @@ -7,7 +7,7 @@ category: Enumerations api: true namespace: errors kind: Enum -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [errors](../index.md) / TextmodeErrorLevel diff --git a/api/textmode.js/namespaces/errors/index.md b/api/textmode.js/namespaces/errors/index.md index 2ff55c56..5a877ccb 100644 --- a/api/textmode.js/namespaces/errors/index.md +++ b/api/textmode.js/namespaces/errors/index.md @@ -6,7 +6,7 @@ description: All error handling related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / errors diff --git a/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md b/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md index 6fd99613..77edd51f 100644 --- a/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md +++ b/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: errors kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md b/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md index 74181a18..57dd5486 100644 --- a/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md +++ b/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: errors kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md index f55d7a92..792c6c6f 100644 --- a/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md +++ b/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: filters kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -65,8 +65,8 @@ true if the filter exists ```ts register( - id, - shader, + id, + shader, uniformDefs?): Promise; ``` diff --git a/api/textmode.js/namespaces/filters/index.md b/api/textmode.js/namespaces/filters/index.md index ffd8f193..2394b848 100644 --- a/api/textmode.js/namespaces/filters/index.md +++ b/api/textmode.js/namespaces/filters/index.md @@ -6,7 +6,7 @@ description: All filter related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / filters diff --git a/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md b/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md index 49faffce..2abcad84 100644 --- a/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md +++ b/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: filters kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/filters/interfaces/FilterContext.md b/api/textmode.js/namespaces/filters/interfaces/FilterContext.md index ffe3be69..56c2c7e5 100644 --- a/api/textmode.js/namespaces/filters/interfaces/FilterContext.md +++ b/api/textmode.js/namespaces/filters/interfaces/FilterContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: filters kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md b/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md index fa49cf75..c64aecf7 100644 --- a/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md +++ b/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: filters kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md b/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md index f257ab00..abb8b7e6 100644 --- a/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md +++ b/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: filters kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [filters](../index.md) / BuiltInFilterName diff --git a/api/textmode.js/namespaces/filters/type-aliases/FilterName.md b/api/textmode.js/namespaces/filters/type-aliases/FilterName.md index 642a68ac..4e1afc2c 100644 --- a/api/textmode.js/namespaces/filters/type-aliases/FilterName.md +++ b/api/textmode.js/namespaces/filters/type-aliases/FilterName.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: filters kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [filters](../index.md) / FilterName diff --git a/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md b/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md index 6b6036fc..c56bbaa5 100644 --- a/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md +++ b/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: filters kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [filters](../index.md) / TextmodeFilterUniformDefinitions diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md index 7531d989..2967305e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: fonts kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md index 916f618d..83385515 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / characterMap diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md index 1bc13cbc..df77145d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / characters diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md index d92a6acc..bc9f1879 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / font diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md index 38393dbb..0e891f93 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / fontSize diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md index 1ecbdbb5..a1a46462 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / framebuffer diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md index e58be092..28648651 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / maxGlyphDimensions diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md index a8c8268e..686df699 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / textureColumns diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md index 16d4dc44..b838640b 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / textureRows diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md index d943b660..8252d21e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeFont namespace: fonts kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeFont](../../TextmodeFont.md) / dispose diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md index a0338af0..9544120d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: fonts kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md index 68804b6d..dbac946e 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / cellDimensions diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md index 8eacc528..c6a47fce 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / cellHeight diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md index fdb3933a..d2bac564 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / cellWidth diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md index ab2fbd88..782599da 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / characterMap diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md index 085fa249..cb63284c 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / characters diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md index c33dba3f..4351d97b 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / columns diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md index 84a422df..c4d07b88 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / fontFramebuffer diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md index ad4e937e..e087650d 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / fontSize diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md index 7019b6f6..e844d83f 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / framebuffer diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md index 24672fdf..496ab2c8 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / maxGlyphDimensions diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md index d07a1ae1..80fb1033 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / nativeCellDimensions diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md index 6fa69c18..330b9002 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / rows diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md index 21b2a383..c1be7ea4 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / textureColumns diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md index d51d948f..037ae0a9 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / textureRows diff --git a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md index 096416f7..40e1230b 100644 --- a/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md +++ b/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTileset namespace: fonts kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [fonts](../../../index.md) / [TextmodeTileset](../../TextmodeTileset.md) / dispose diff --git a/api/textmode.js/namespaces/fonts/index.md b/api/textmode.js/namespaces/fonts/index.md index d741cf3a..e2f746ef 100644 --- a/api/textmode.js/namespaces/fonts/index.md +++ b/api/textmode.js/namespaces/fonts/index.md @@ -6,7 +6,7 @@ description: All font rendering related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / fonts diff --git a/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md b/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md index 4daf9e3f..0929b8b6 100644 --- a/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md +++ b/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: fonts kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md b/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md index 99580684..d002e482 100644 --- a/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md +++ b/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: fonts kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md b/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md index a50de83a..43c0c177 100644 --- a/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md +++ b/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: fonts kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md b/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md index 53ba4e00..ae2d7470 100644 --- a/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md +++ b/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: fonts kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md b/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md index 59c61504..3bba4850 100644 --- a/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md +++ b/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: fonts kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [fonts](../index.md) / TextmodeGlyph diff --git a/api/textmode.js/namespaces/input/index.md b/api/textmode.js/namespaces/input/index.md index c0b5e927..3c9c0c43 100644 --- a/api/textmode.js/namespaces/input/index.md +++ b/api/textmode.js/namespaces/input/index.md @@ -6,7 +6,7 @@ description: All types and interfaces related to input event handling. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / input diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/index.md b/api/textmode.js/namespaces/input/namespaces/gamepad/index.md index 8e900764..6731a594 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/index.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/index.md @@ -7,7 +7,7 @@ category: Namespaces api: true namespace: input kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../index.md) / [input](../../index.md) / gamepad diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md index e8a41c34..0e69ca5e 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md index e2a9734e..79a969b2 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md index ff8366d6..b7d1b629 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md index e5d7080e..4aea0009 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md index 4d7e30bb..d423d28a 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md index 64bb98a3..547d9359 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md index 3e5e3fac..2bfa2c0b 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md index 7ad24bd3..e537deca 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.gamepad kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md index ad2bb5e3..2ce04c5f 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.gamepad kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / GamepadAxisEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md index e7e191d8..79760aab 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.gamepad kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / GamepadButtonEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md index 10a9d0db..62670d34 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.gamepad kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / GamepadConnectionEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md index 2d7161b4..c7609f7c 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.gamepad kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / TextmodeStandardAxisName diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md index 101fa7db..f8592299 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.gamepad kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / TextmodeStandardButtonName @@ -15,7 +15,7 @@ lastModified: 2026-07-31 # Type Alias: TextmodeStandardButtonName ```ts -type TextmodeStandardButtonName = +type TextmodeStandardButtonName = | "south" | "east" | "west" diff --git a/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md b/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md index d1db910a..d6b486d7 100644 --- a/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input.gamepad kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [gamepad](../index.md) / GAMEPAD\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/input/namespaces/keyboard/index.md b/api/textmode.js/namespaces/input/namespaces/keyboard/index.md index 1230154a..856e3b1a 100644 --- a/api/textmode.js/namespaces/input/namespaces/keyboard/index.md +++ b/api/textmode.js/namespaces/input/namespaces/keyboard/index.md @@ -7,7 +7,7 @@ category: Namespaces api: true namespace: input kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../index.md) / [input](../../index.md) / keyboard diff --git a/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md b/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md index 518ad265..ea5fd8ab 100644 --- a/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.keyboard kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md b/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md index 702e990f..59f749e2 100644 --- a/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md +++ b/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.keyboard kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md b/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md index db457468..f5424c3f 100644 --- a/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.keyboard kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [keyboard](../index.md) / KeyboardEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md b/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md index ae7224a3..756ade6f 100644 --- a/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input.keyboard kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [keyboard](../index.md) / KEYBOARD\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/index.md b/api/textmode.js/namespaces/input/namespaces/mouse/index.md index 5be72b8f..77c6a8da 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/index.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/index.md @@ -7,7 +7,7 @@ category: Namespaces api: true namespace: input kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../index.md) / [input](../../index.md) / mouse diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md b/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md index fb0b1fa9..bf21bb0c 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.mouse kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md b/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md index e283e67f..c79850cf 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.mouse kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md b/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md index 13f683ce..1f0ac835 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.mouse kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [mouse](../index.md) / MouseEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md b/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md index 1163059b..8ed588fc 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.mouse kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [mouse](../index.md) / MousePosition diff --git a/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md b/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md index 9e285a06..4517a047 100644 --- a/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input.mouse kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [mouse](../index.md) / MOUSE\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/input/namespaces/touch/index.md b/api/textmode.js/namespaces/input/namespaces/touch/index.md index 86c1a25e..31ca2089 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/index.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/index.md @@ -7,7 +7,7 @@ category: Namespaces api: true namespace: input kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../index.md) / [input](../../index.md) / touch diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md index d9042551..b06a9a87 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md index 312179b2..1195d569 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md index 2bf25568..7a846dd8 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md index c4db84a8..69c21d4e 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md index 0836df8c..93ab2f17 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md index db2db425..62a6c0ed 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md index d56cd128..a34d5a79 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md index f09f5d81..69f20fbc 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: input.touch kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md index 886e9e21..bbdb288e 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchEventHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md index 2b2b36bf..6372f6b5 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchLongPressHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md index 354c5b29..a04a8723 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchPinchHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md index b9c2deba..5f47285b 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchRotateHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md index aa42e8ec..f0466c1c 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchSwipeHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md index e194ebed..c8e34428 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input.touch kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TouchTapHandler diff --git a/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md b/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md index 8c621dec..d7446ee4 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input.touch kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / GESTURE\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md b/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md index 2f0ce3ec..c9bd81e1 100644 --- a/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input.touch kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [input](../../../index.md) / [touch](../index.md) / TOUCH\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md b/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md index 74f63ae9..def8add4 100644 --- a/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md +++ b/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [input](../index.md) / InputEventMap diff --git a/api/textmode.js/namespaces/input/type-aliases/InputEventName.md b/api/textmode.js/namespaces/input/type-aliases/InputEventName.md index da2b6892..1f110cc4 100644 --- a/api/textmode.js/namespaces/input/type-aliases/InputEventName.md +++ b/api/textmode.js/namespaces/input/type-aliases/InputEventName.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [input](../index.md) / InputEventName diff --git a/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md b/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md index 714c902a..9f18e9a6 100644 --- a/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md +++ b/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: input kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [input](../index.md) / InputEventOwner diff --git a/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md b/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md index 4f5739dd..a7a5db98 100644 --- a/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md +++ b/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md @@ -7,7 +7,7 @@ category: Variables api: true namespace: input kind: Variable -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [input](../index.md) / INPUT\_EVENT\_NAMES diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md index d46d791f..dc7d664a 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: layering kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -31,43 +31,75 @@ The base layer, which is always present at the bottom of the layer stack, can be accessed via [Textmodifier.layers](../../../classes/Textmodifier/accessors/layers.md) as `t.layers.base`. -## Accessors +## Cameras & projection -| Accessor | Description | +Create and configure the camera used while rendering this layer. + +| Method | Description | | ------ | ------ | -| [asciiFramebuffer](TextmodeLayer/accessors/asciiFramebuffer.md) | Framebuffer containing this layer's rendered textmode output. | -| [drawFramebuffer](TextmodeLayer/accessors/drawFramebuffer.md) | Draw framebuffer for this layer. | -| [font](TextmodeLayer/accessors/font.md) | Font or tileset used by this layer. | -| [grid](TextmodeLayer/accessors/grid.md) | Grid associated with this layer. | -| [height](TextmodeLayer/accessors/height.md) | Height of the final ASCII framebuffer in pixels. | -| [texture](TextmodeLayer/accessors/texture.md) | WebGL texture of the final ASCII framebuffer. | -| [width](TextmodeLayer/accessors/width.md) | Width of the final ASCII framebuffer in pixels. | +| [camera](TextmodeLayer/methods/camera.md) | Set explicit camera parameters for this layer. | +| [createCamera](TextmodeLayer/methods/createCamera.md) | Create and activate a camera initialized from this layer's camera state. | +| [lookAt](TextmodeLayer/methods/lookAt.md) | Update this layer camera's target and optional up vector. | +| [ortho](TextmodeLayer/methods/ortho.md) | Enable orthographic projection for this layer. | +| [perspective](TextmodeLayer/methods/perspective.md) | Enable perspective projection for this layer. | +| [resetCamera](TextmodeLayer/methods/resetCamera.md) | Reset this layer to default auto camera behavior. | +| [setCamera](TextmodeLayer/methods/setCamera.md) | Activate a camera for this layer. | + +## Compositing & visibility -## Methods +Adjust the layer's opacity, blend mode, position, rotation, and filters. | Method | Description | | ------ | ------ | | [blendMode](TextmodeLayer/methods/blendMode.md) | Set or get this layer's blend mode. | -| [camera](TextmodeLayer/methods/camera.md) | Set explicit camera parameters for this layer. | -| [createCamera](TextmodeLayer/methods/createCamera.md) | Create and activate a camera initialized from this layer's camera state. | -| [deletePluginState](TextmodeLayer/methods/deletePluginState.md) | Delete plugin-specific state from this layer. | -| [draw](TextmodeLayer/methods/draw.md) | Set this layer's draw callback. | | [filter](TextmodeLayer/methods/filter.md) | Queue a post-processing filter for this layer. | +| [offset](TextmodeLayer/methods/offset.md) | Set or get this layer's compositing offset in pixels. | +| [opacity](TextmodeLayer/methods/opacity.md) | Set or get this layer's opacity. | +| [rotateZ](TextmodeLayer/methods/rotateZ.md) | Set or get this layer's compositing rotation in degrees. | + +## Grid, fonts & glyphs + +Configure the layer-specific grid and glyph source. + +| Method | Description | +| ------ | ------ | | [fontSize](TextmodeLayer/methods/fontSize.md) | Get or set this layer's font size. | -| [getPluginState](TextmodeLayer/methods/getPluginState.md) | Retrieve plugin-specific state stored on this layer. | -| [hasPluginState](TextmodeLayer/methods/hasPluginState.md) | Check whether plugin-specific state exists on this layer. | -| [hide](TextmodeLayer/methods/hide.md) | Hide this layer from rendering. | | [loadFont](TextmodeLayer/methods/loadFont.md) | Load a font into this layer from a URL/path or existing [TextmodeFont](../../fonts/classes/TextmodeFont.md). | | [loadTileset](TextmodeLayer/methods/loadTileset.md) | Load a tileset into this layer from options or an existing [TextmodeTileset](../../fonts/classes/TextmodeTileset.md). | -| [lookAt](TextmodeLayer/methods/lookAt.md) | Update this layer camera's target and optional up vector. | -| [offset](TextmodeLayer/methods/offset.md) | Set or get this layer's compositing offset in pixels. | -| [opacity](TextmodeLayer/methods/opacity.md) | Set or get this layer's opacity. | -| [ortho](TextmodeLayer/methods/ortho.md) | Enable orthographic projection for this layer. | -| [perspective](TextmodeLayer/methods/perspective.md) | Enable perspective projection for this layer. | +| [useTileColors](TextmodeLayer/methods/useTileColors.md) | Configure authored tileset color preservation for this layer. | + +## Layer lifecycle + +Set a layer's drawing callbacks and control whether it is visible. + +| Method | Description | +| ------ | ------ | +| [draw](TextmodeLayer/methods/draw.md) | Set this layer's draw callback. | +| [hide](TextmodeLayer/methods/hide.md) | Hide this layer from rendering. | | [postDraw](TextmodeLayer/methods/postDraw.md) | Set this layer's post-draw callback. | -| [resetCamera](TextmodeLayer/methods/resetCamera.md) | Reset this layer to default auto camera behavior. | -| [rotateZ](TextmodeLayer/methods/rotateZ.md) | Set or get this layer's compositing rotation in degrees. | -| [setCamera](TextmodeLayer/methods/setCamera.md) | Activate a camera for this layer. | -| [setPluginState](TextmodeLayer/methods/setPluginState.md) | Store plugin-specific state on this layer. Plugins can use this to attach their own data to layer instances. | | [show](TextmodeLayer/methods/show.md) | Show this layer for rendering. | -| [useTileColors](TextmodeLayer/methods/useTileColors.md) | Configure authored tileset color preservation for this layer. | + +## Plugin state + +Store state owned by a plugin on this layer. + +| Method | Description | +| ------ | ------ | +| [deletePluginState](TextmodeLayer/methods/deletePluginState.md) | Delete plugin-specific state from this layer. | +| [getPluginState](TextmodeLayer/methods/getPluginState.md) | Retrieve plugin-specific state stored on this layer. | +| [hasPluginState](TextmodeLayer/methods/hasPluginState.md) | Check whether plugin-specific state exists on this layer. | +| [setPluginState](TextmodeLayer/methods/setPluginState.md) | Store plugin-specific state on this layer. Plugins can use this to attach their own data to layer instances. | + +## Render outputs + +Read the layer's texture, dimensions, and intermediate framebuffers. + +| Accessor | Description | +| ------ | ------ | +| [asciiFramebuffer](TextmodeLayer/accessors/asciiFramebuffer.md) | Framebuffer containing this layer's rendered textmode output. | +| [drawFramebuffer](TextmodeLayer/accessors/drawFramebuffer.md) | Draw framebuffer for this layer. | +| [font](TextmodeLayer/accessors/font.md) | Font or tileset used by this layer. | +| [grid](TextmodeLayer/accessors/grid.md) | Grid associated with this layer. | +| [height](TextmodeLayer/accessors/height.md) | Height of the final ASCII framebuffer in pixels. | +| [texture](TextmodeLayer/accessors/texture.md) | WebGL texture of the final ASCII framebuffer. | +| [width](TextmodeLayer/accessors/width.md) | Width of the final ASCII framebuffer in pixels. | diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md index 8fdff5a2..7a8023d8 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / asciiFramebuffer @@ -18,7 +18,7 @@ lastModified: 2026-07-31 ## Get Signature ```ts -get asciiFramebuffer(): +get asciiFramebuffer(): | TextmodeFramebuffer | undefined; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md index 53f5250e..a56784bd 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / drawFramebuffer @@ -18,7 +18,7 @@ lastModified: 2026-07-31 ## Get Signature ```ts -get drawFramebuffer(): +get drawFramebuffer(): | TextmodeFramebuffer | undefined; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md index 0bf49d83..fd25e979 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / font @@ -18,7 +18,7 @@ lastModified: 2026-07-31 ## Get Signature ```ts -get font(): +get font(): | TextmodeFont | TextmodeTileset; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md index 7e04831d..4c832244 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / grid diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md index 93e750ab..1d4a9811 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / height diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md index 5b7dc748..80b49c93 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / texture diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md index 37529e78..ab0b5fe0 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / width diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md index 211be98f..ef8030e7 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / blendMode diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md index 88007f9b..e9519e73 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / camera @@ -17,14 +17,14 @@ lastModified: 2026-07-31 ```ts camera( - eyeX, - eyeY, - eyeZ, - targetX?, - targetY?, - targetZ?, - upX?, - upY?, + eyeX, + eyeY, + eyeZ, + targetX?, + targetY?, + targetZ?, + upX?, + upY?, upZ?): void; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md index 1de172b9..b1079569 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / createCamera diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md index e3af5c3c..a344773a 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / deletePluginState diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md index 61ad23f2..43b6c0e6 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / draw diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md index b32d5be9..dce7d79d 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / filter diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md index 350e9257..a1e84027 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / fontSize diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md index 5668b0ee..bf9114c4 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / getPluginState diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md index 68811606..8eca70b9 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / hasPluginState diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md index 136a9319..46f1c450 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / hide diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md index e67c9d70..cc0816e0 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / loadFont diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md index df1206d7..4685afb8 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / loadTileset diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md index a4a339f5..fc4ff55d 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / lookAt @@ -17,11 +17,11 @@ lastModified: 2026-07-31 ```ts lookAt( - targetX, - targetY, - targetZ, - upX?, - upY?, + targetX, + targetY, + targetZ, + upX?, + upY?, upZ?): void; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md index ae711cf5..6bd53220 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / offset @@ -16,7 +16,7 @@ lastModified: 2026-07-31 # Method: offset() ```ts -offset(x?, y?): +offset(x?, y?): | void | { x: number; diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md index c4ad4ba0..8fadd548 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / opacity diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md index 6664d401..041a1195 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / ortho diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md index 9ffab38d..29c9459c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / perspective @@ -17,8 +17,8 @@ lastModified: 2026-07-31 ```ts perspective( - fov?, - near?, + fov?, + near?, far?): void; ``` diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md index 58eb8075..5b606dd3 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / postDraw diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md index 3ab9585b..def1b272 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / resetCamera diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md index 1a075fde..17b33ca8 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / rotateZ diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md index 04f9b9c7..629ca0fd 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / setCamera diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md index 04519f02..f166d97f 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / setPluginState diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md index cfcaac76..74d55487 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / show diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md index 9f6a4896..a17c14ff 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayer namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayer](../../TextmodeLayer.md) / useTileColors diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md index 457477c7..3fffcc92 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: layering kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md index e7bd4629..2a2d55bf 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / all diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md index e07769cf..e27dfb51 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / base diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md index a7456949..1e6d20da 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / filters diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md index ca1cdaaf..8dae7ff2 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / resultFramebuffer diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md index d25bfbe7..7076c482 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / add diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md index 1d55b8e6..cbd33ce9 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / clear diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md index 7c2cc25b..97d78e1c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / move diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md index b7c86788..30f9500c 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / remove diff --git a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md index ac017c46..d009bf11 100644 --- a/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md +++ b/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md @@ -8,7 +8,7 @@ api: true owner: TextmodeLayerManager namespace: layering kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [layering](../../../index.md) / [TextmodeLayerManager](../../TextmodeLayerManager.md) / swap diff --git a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md index a9e3c54c..f0fc6ae7 100644 --- a/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md +++ b/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md @@ -7,7 +7,7 @@ category: Enumerations api: true namespace: layering kind: Enum -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [layering](../index.md) / LayerBlendMode diff --git a/api/textmode.js/namespaces/layering/index.md b/api/textmode.js/namespaces/layering/index.md index d00c0784..06c83a0d 100644 --- a/api/textmode.js/namespaces/layering/index.md +++ b/api/textmode.js/namespaces/layering/index.md @@ -6,7 +6,7 @@ description: All modules and types related to multi-layered textmode rendering. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / layering diff --git a/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md b/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md index df7f64b1..4c05420b 100644 --- a/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md +++ b/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: layering kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md b/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md index a68bf4fb..8aaf4f8c 100644 --- a/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md +++ b/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: loading kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- diff --git a/api/textmode.js/namespaces/loading/index.md b/api/textmode.js/namespaces/loading/index.md index 97e68a82..019bfdf7 100644 --- a/api/textmode.js/namespaces/loading/index.md +++ b/api/textmode.js/namespaces/loading/index.md @@ -6,7 +6,7 @@ description: All loading screen related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / loading diff --git a/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md b/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md index e243a089..d09b3d11 100644 --- a/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md +++ b/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: loading kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md b/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md index a4283c28..2aeabd96 100644 --- a/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md +++ b/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: loading kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md b/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md index 398f7482..ec2c00f1 100644 --- a/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md +++ b/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: loading kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [loading](../index.md) / LoadingScreenState diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage.md b/api/textmode.js/namespaces/media/classes/TextmodeImage.md index 0e9a0441..85761204 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: media kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -28,32 +28,47 @@ and configure conversion through inherited chainable methods. - [`TextmodeSource`](TextmodeSource.md) -## Accessors - -| Accessor | Description | -| ------ | ------ | -| [height](TextmodeImage/accessors/height.md) | Ideal draw height in grid cells. | -| [originalHeight](TextmodeImage/accessors/originalHeight.md) | Original source height in pixels. | -| [originalWidth](TextmodeImage/accessors/originalWidth.md) | Original source width in pixels. | -| [texture](TextmodeImage/accessors/texture.md) | WebGL texture backing this source. | -| [width](TextmodeImage/accessors/width.md) | Ideal draw width in grid cells. | - -## Methods +## Character & color mapping | Method | Description | | ------ | ------ | | [background](TextmodeImage/methods/background.md) | Set the background color used for transparent pixels. | -| [brightnessRange](TextmodeImage/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [cellColor](TextmodeImage/methods/cellColor.md) | Set the cell color used when [cellColorMode](TextmodeSource/methods/cellColorMode.md) is `'fixed'`. | | [cellColorMode](TextmodeImage/methods/cellColorMode.md) | Set whether cell color is sampled from the source or fixed. | | [characters](TextmodeImage/methods/characters.md) | Set the characters used for brightness mapping. | | [charColor](TextmodeImage/methods/charColor.md) | Set the character color used when [charColorMode](TextmodeSource/methods/charColorMode.md) is `'fixed'`. | | [charColorMode](TextmodeImage/methods/charColorMode.md) | Set whether character color is sampled from the source or fixed. | -| [charRotation](TextmodeImage/methods/charRotation.md) | Rotate generated characters. | + +## Conversion + +| Method | Description | +| ------ | ------ | +| [brightnessRange](TextmodeImage/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [clearConversions](TextmodeImage/methods/clearConversions.md) | Clear this source's conversion stack and return to single-mode conversion. | | [conversionMode](TextmodeImage/methods/conversionMode.md) | Select the conversion mode for this source. | | [conversions](TextmodeImage/methods/conversions.md) | Set an ordered conversion stack for this source. | + +## Resource lifecycle + +| Method | Description | +| ------ | ------ | | [dispose](TextmodeImage/methods/dispose.md) | Dispose of the resource and free associated WebGL textures. | + +## Source dimensions + +| Accessor | Description | +| ------ | ------ | +| [height](TextmodeImage/accessors/height.md) | Ideal draw height in grid cells. | +| [originalHeight](TextmodeImage/accessors/originalHeight.md) | Original source height in pixels. | +| [originalWidth](TextmodeImage/accessors/originalWidth.md) | Original source width in pixels. | +| [texture](TextmodeImage/accessors/texture.md) | WebGL texture backing this source. | +| [width](TextmodeImage/accessors/width.md) | Ideal draw width in grid cells. | + +## Source transforms + +| Method | Description | +| ------ | ------ | +| [charRotation](TextmodeImage/methods/charRotation.md) | Rotate generated characters. | | [flipX](TextmodeImage/methods/flipX.md) | Flip the source horizontally. | | [flipY](TextmodeImage/methods/flipY.md) | Flip the source vertically. | | [invert](TextmodeImage/methods/invert.md) | Enable or disable source color inversion. | diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md index 54cdfbc2..ed57bcbf 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / height diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md index cb01d369..e5cc84bd 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / originalHeight diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md index bec7a609..994672fc 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / originalWidth diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md index a56d7890..6c6708ee 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / texture diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md index d1c72b5a..b98b3351 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / width diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md index b93ec415..520af0f4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / background @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts background( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md index efc1e389..3ba9dbd9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / brightnessRange diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md index 0471d8aa..25589a6b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / cellColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts cellColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md index 2eb2ccb0..ead56b99 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / cellColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md index f4b2f769..510acfe2 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / charColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts charColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md index c5ac1727..c4cd5115 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / charColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md index 61fe787d..5b3822eb 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / charRotation diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md index fab2da67..a8fe965f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / characters diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md index b3e62ab4..da033e72 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / clearConversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md index de1edc0c..fbd6b01a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / conversionMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md index 928bb553..eb975477 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / conversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md index 8583dccb..6e11fe7b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / dispose diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md index 3a0a8391..b1441350 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / flipX diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md index e94aca69..5742c090 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / flipY diff --git a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md index 4edeb65f..47e3048f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md @@ -8,7 +8,7 @@ api: true owner: TextmodeImage namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeImage](../../TextmodeImage.md) / invert diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource.md b/api/textmode.js/namespaces/media/classes/TextmodeSource.md index e3907e5b..3b75544b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: media kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -27,32 +27,57 @@ Shared base for image, video, and dynamic texture sources drawn with [Textmodifi - [`TextmodeImage`](TextmodeImage.md) - [`TextmodeTexture`](TextmodeTexture.md) -## Accessors +## Character & color mapping -| Accessor | Description | -| ------ | ------ | -| [height](TextmodeSource/accessors/height.md) | Ideal draw height in grid cells. | -| [originalHeight](TextmodeSource/accessors/originalHeight.md) | Original source height in pixels. | -| [originalWidth](TextmodeSource/accessors/originalWidth.md) | Original source width in pixels. | -| [texture](TextmodeSource/accessors/texture.md) | WebGL texture backing this source. | -| [width](TextmodeSource/accessors/width.md) | Ideal draw width in grid cells. | - -## Methods +Map sampled values to glyphs, foreground colors, cell colors, and a background. | Method | Description | | ------ | ------ | | [background](TextmodeSource/methods/background.md) | Set the background color used for transparent pixels. | -| [brightnessRange](TextmodeSource/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [cellColor](TextmodeSource/methods/cellColor.md) | Set the cell color used when [cellColorMode](TextmodeSource/methods/cellColorMode.md) is `'fixed'`. | | [cellColorMode](TextmodeSource/methods/cellColorMode.md) | Set whether cell color is sampled from the source or fixed. | | [characters](TextmodeSource/methods/characters.md) | Set the characters used for brightness mapping. | | [charColor](TextmodeSource/methods/charColor.md) | Set the character color used when [charColorMode](TextmodeSource/methods/charColorMode.md) is `'fixed'`. | | [charColorMode](TextmodeSource/methods/charColorMode.md) | Set whether character color is sampled from the source or fixed. | -| [charRotation](TextmodeSource/methods/charRotation.md) | Rotate generated characters. | + +## Conversion + +Select and clear the conversion stack used when drawing this source. + +| Method | Description | +| ------ | ------ | +| [brightnessRange](TextmodeSource/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [clearConversions](TextmodeSource/methods/clearConversions.md) | Clear this source's conversion stack and return to single-mode conversion. | | [conversionMode](TextmodeSource/methods/conversionMode.md) | Select the conversion mode for this source. | | [conversions](TextmodeSource/methods/conversions.md) | Set an ordered conversion stack for this source. | + +## Resource lifecycle + +Release the WebGL resources owned by the source. + +| Method | Description | +| ------ | ------ | | [dispose](TextmodeSource/methods/dispose.md) | Dispose of the resource and free associated WebGL textures. | + +## Source dimensions + +Inspect the source texture and its original and grid-fitted dimensions. + +| Accessor | Description | +| ------ | ------ | +| [height](TextmodeSource/accessors/height.md) | Ideal draw height in grid cells. | +| [originalHeight](TextmodeSource/accessors/originalHeight.md) | Original source height in pixels. | +| [originalWidth](TextmodeSource/accessors/originalWidth.md) | Original source width in pixels. | +| [texture](TextmodeSource/accessors/texture.md) | WebGL texture backing this source. | +| [width](TextmodeSource/accessors/width.md) | Ideal draw width in grid cells. | + +## Source transforms + +Mirror, invert, or rotate the source's converted output. + +| Method | Description | +| ------ | ------ | +| [charRotation](TextmodeSource/methods/charRotation.md) | Rotate generated characters. | | [flipX](TextmodeSource/methods/flipX.md) | Flip the source horizontally. | | [flipY](TextmodeSource/methods/flipY.md) | Flip the source vertically. | | [invert](TextmodeSource/methods/invert.md) | Enable or disable source color inversion. | diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md index c4cd5613..ad93c9b6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / height diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md index 8eef9b22..b76696db 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / originalHeight diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md index 8c964474..6c5d1c10 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / originalWidth diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md index a081044c..52d121d6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / texture diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md index 0a18da9d..28f7d1d7 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / width diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md index ba90d41e..9271a7b8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / background @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts background( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md index 24f09532..1ee33986 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / brightnessRange diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md index 6a83b248..23d33cf1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / cellColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts cellColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md index b5949740..e996700b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / cellColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md index 40de00c8..1747403e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / charColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts charColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md index 4902d066..416411fd 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / charColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md index b010857f..bb943ccf 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / charRotation diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md index bbe45d53..52e8465e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / characters diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md index ea702ffa..df8f81f1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / clearConversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md index fd7235ae..7dbe1e07 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / conversionMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md index bc39b77b..04c2a476 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / conversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md index cf7c4c0b..714271e3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / dispose diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md index 8239d1e3..be3ba4b6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / flipX diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md index be33323e..7f439a3c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / flipY diff --git a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md index 206a3e4f..72261490 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md @@ -8,7 +8,7 @@ api: true owner: TextmodeSource namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeSource](../../TextmodeSource.md) / invert diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture.md index b5670b50..37b1585a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: media kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -30,33 +30,53 @@ renderers such as three.js, p5.js, Babylon.js, or hydra-synth. - [`TextmodeVideo`](TextmodeVideo.md) -## Accessors - -| Accessor | Description | -| ------ | ------ | -| [height](TextmodeTexture/accessors/height.md) | Ideal draw height in grid cells. | -| [originalHeight](TextmodeTexture/accessors/originalHeight.md) | Original source height in pixels. | -| [originalWidth](TextmodeTexture/accessors/originalWidth.md) | Original source width in pixels. | -| [source](TextmodeTexture/accessors/source.md) | Source element this texture captures. | -| [texture](TextmodeTexture/accessors/texture.md) | WebGL texture backing this source. | -| [width](TextmodeTexture/accessors/width.md) | Ideal draw width in grid cells. | - -## Methods +## Character & color mapping | Method | Description | | ------ | ------ | | [background](TextmodeTexture/methods/background.md) | Set the background color used for transparent pixels. | -| [brightnessRange](TextmodeTexture/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [cellColor](TextmodeTexture/methods/cellColor.md) | Set the cell color used when [cellColorMode](TextmodeSource/methods/cellColorMode.md) is `'fixed'`. | | [cellColorMode](TextmodeTexture/methods/cellColorMode.md) | Set whether cell color is sampled from the source or fixed. | | [characters](TextmodeTexture/methods/characters.md) | Set the characters used for brightness mapping. | | [charColor](TextmodeTexture/methods/charColor.md) | Set the character color used when [charColorMode](TextmodeSource/methods/charColorMode.md) is `'fixed'`. | | [charColorMode](TextmodeTexture/methods/charColorMode.md) | Set whether character color is sampled from the source or fixed. | -| [charRotation](TextmodeTexture/methods/charRotation.md) | Rotate generated characters. | + +## Conversion + +| Method | Description | +| ------ | ------ | +| [brightnessRange](TextmodeTexture/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [clearConversions](TextmodeTexture/methods/clearConversions.md) | Clear this source's conversion stack and return to single-mode conversion. | | [conversionMode](TextmodeTexture/methods/conversionMode.md) | Select the conversion mode for this source. | | [conversions](TextmodeTexture/methods/conversions.md) | Set an ordered conversion stack for this source. | + +## Other + +| Accessor | Description | +| ------ | ------ | +| [source](TextmodeTexture/accessors/source.md) | Source element this texture captures. | + +## Resource lifecycle + +| Method | Description | +| ------ | ------ | | [dispose](TextmodeTexture/methods/dispose.md) | Dispose of the resource and free associated WebGL textures. | + +## Source dimensions + +| Accessor | Description | +| ------ | ------ | +| [height](TextmodeTexture/accessors/height.md) | Ideal draw height in grid cells. | +| [originalHeight](TextmodeTexture/accessors/originalHeight.md) | Original source height in pixels. | +| [originalWidth](TextmodeTexture/accessors/originalWidth.md) | Original source width in pixels. | +| [texture](TextmodeTexture/accessors/texture.md) | WebGL texture backing this source. | +| [width](TextmodeTexture/accessors/width.md) | Ideal draw width in grid cells. | + +## Source transforms + +| Method | Description | +| ------ | ------ | +| [charRotation](TextmodeTexture/methods/charRotation.md) | Rotate generated characters. | | [flipX](TextmodeTexture/methods/flipX.md) | Flip the source horizontally. | | [flipY](TextmodeTexture/methods/flipY.md) | Flip the source vertically. | | [invert](TextmodeTexture/methods/invert.md) | Enable or disable source color inversion. | diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md index 90503f49..1d61c21e 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / height diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md index 1cb74f19..468543a1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / originalHeight diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md index 26cc46d5..abb4a3b1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / originalWidth diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md index f841980e..5b80a233 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / source diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md index 8b9abf25..fbd14090 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / texture diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md index 8a3b37b4..24dee480 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / width diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md index 3e6e99ba..fee9ef58 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / background @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts background( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md index d712254c..774b1f34 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / brightnessRange diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md index e8c561b8..ffced722 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / cellColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts cellColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md index e1ca7876..bb28e2d6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / cellColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md index 71b20ee9..10e6791d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / charColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts charColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md index 31790ac1..7ec5649d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / charColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md index a6a6024b..482eefff 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / charRotation diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md index ddc50f34..0eac86a6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / characters diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md index 5f1672fe..0230cbdb 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / clearConversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md index c1653157..ba5d9bb0 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / conversionMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md index 82f6faf6..204897ab 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / conversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md index e3c4c05e..6228d2b6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / dispose diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md index 5c1678d4..9aadc80b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / flipX diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md index 3fc50469..5d2f942f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / flipY diff --git a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md index 234bd1fc..c2fb3414 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md @@ -8,7 +8,7 @@ api: true owner: TextmodeTexture namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeTexture](../../TextmodeTexture.md) / invert diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md index 7357b9fe..85730456 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo.md @@ -7,7 +7,7 @@ category: Classes api: true namespace: media kind: Class -lastModified: 2026-07-31 +lastModified: 2026-08-02 hasConstructor: false --- @@ -29,40 +29,38 @@ chainable methods. - [`TextmodeTexture`](TextmodeTexture.md) -## Accessors - -| Accessor | Description | -| ------ | ------ | -| [currentTime](TextmodeVideo/accessors/currentTime.md) | Current playback time in seconds. | -| [duration](TextmodeVideo/accessors/duration.md) | Total video duration in seconds. | -| [height](TextmodeVideo/accessors/height.md) | Ideal draw height in grid cells. | -| [isPlaying](TextmodeVideo/accessors/isPlaying.md) | Whether the video is currently playing. | -| [originalHeight](TextmodeVideo/accessors/originalHeight.md) | Original source height in pixels. | -| [originalWidth](TextmodeVideo/accessors/originalWidth.md) | Original source width in pixels. | -| [source](TextmodeVideo/accessors/source.md) | Source element this texture captures. | -| [texture](TextmodeVideo/accessors/texture.md) | WebGL texture backing this source. | -| [videoElement](TextmodeVideo/accessors/videoElement.md) | Underlying HTML video element. | -| [width](TextmodeVideo/accessors/width.md) | Ideal draw width in grid cells. | - -## Methods +## Character & color mapping | Method | Description | | ------ | ------ | | [background](TextmodeVideo/methods/background.md) | Set the background color used for transparent pixels. | -| [brightnessRange](TextmodeVideo/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [cellColor](TextmodeVideo/methods/cellColor.md) | Set the cell color used when [cellColorMode](TextmodeSource/methods/cellColorMode.md) is `'fixed'`. | | [cellColorMode](TextmodeVideo/methods/cellColorMode.md) | Set whether cell color is sampled from the source or fixed. | | [characters](TextmodeVideo/methods/characters.md) | Set the characters used for brightness mapping. | | [charColor](TextmodeVideo/methods/charColor.md) | Set the character color used when [charColorMode](TextmodeSource/methods/charColorMode.md) is `'fixed'`. | | [charColorMode](TextmodeVideo/methods/charColorMode.md) | Set whether character color is sampled from the source or fixed. | -| [charRotation](TextmodeVideo/methods/charRotation.md) | Rotate generated characters. | + +## Conversion + +| Method | Description | +| ------ | ------ | +| [brightnessRange](TextmodeVideo/methods/brightnessRange.md) | Capture only source pixels whose brightness is inside the inclusive byte range. | | [clearConversions](TextmodeVideo/methods/clearConversions.md) | Clear this source's conversion stack and return to single-mode conversion. | | [conversionMode](TextmodeVideo/methods/conversionMode.md) | Select the conversion mode for this source. | | [conversions](TextmodeVideo/methods/conversions.md) | Set an ordered conversion stack for this source. | -| [dispose](TextmodeVideo/methods/dispose.md) | Dispose the video source and release the backing media element. | -| [flipX](TextmodeVideo/methods/flipX.md) | Flip the source horizontally. | -| [flipY](TextmodeVideo/methods/flipY.md) | Flip the source vertically. | -| [invert](TextmodeVideo/methods/invert.md) | Enable or disable source color inversion. | + +## Other + +| Accessor | Description | +| ------ | ------ | +| [source](TextmodeVideo/accessors/source.md) | Source element this texture captures. | + +## Playback + +Start, pause, stop, seek, loop, and adjust the speed or volume. + +| Method | Description | +| ------ | ------ | | [loop](TextmodeVideo/methods/loop.md) | Set whether the video loops. | | [pause](TextmodeVideo/methods/pause.md) | Pause video playback. | | [play](TextmodeVideo/methods/play.md) | Start video playback. | @@ -70,3 +68,39 @@ chainable methods. | [stop](TextmodeVideo/methods/stop.md) | Stop the video and seek to the beginning. | | [time](TextmodeVideo/methods/time.md) | Seek to a playback time. | | [volume](TextmodeVideo/methods/volume.md) | Set playback volume. | + +## Playback state + +Read the underlying video element and its current timing state. + +| Accessor | Description | +| ------ | ------ | +| [currentTime](TextmodeVideo/accessors/currentTime.md) | Current playback time in seconds. | +| [duration](TextmodeVideo/accessors/duration.md) | Total video duration in seconds. | +| [isPlaying](TextmodeVideo/accessors/isPlaying.md) | Whether the video is currently playing. | +| [videoElement](TextmodeVideo/accessors/videoElement.md) | Underlying HTML video element. | + +## Resource lifecycle + +| Method | Description | +| ------ | ------ | +| [dispose](TextmodeVideo/methods/dispose.md) | Dispose the video source and release the backing media element. | + +## Source dimensions + +| Accessor | Description | +| ------ | ------ | +| [height](TextmodeVideo/accessors/height.md) | Ideal draw height in grid cells. | +| [originalHeight](TextmodeVideo/accessors/originalHeight.md) | Original source height in pixels. | +| [originalWidth](TextmodeVideo/accessors/originalWidth.md) | Original source width in pixels. | +| [texture](TextmodeVideo/accessors/texture.md) | WebGL texture backing this source. | +| [width](TextmodeVideo/accessors/width.md) | Ideal draw width in grid cells. | + +## Source transforms + +| Method | Description | +| ------ | ------ | +| [charRotation](TextmodeVideo/methods/charRotation.md) | Rotate generated characters. | +| [flipX](TextmodeVideo/methods/flipX.md) | Flip the source horizontally. | +| [flipY](TextmodeVideo/methods/flipY.md) | Flip the source vertically. | +| [invert](TextmodeVideo/methods/invert.md) | Enable or disable source color inversion. | diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md index 0ef2a78c..a5412ad5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / currentTime diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md index c31de6e5..0bf95d2b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / duration diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md index 2d9049f7..feac00c7 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / height diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md index 64aaa6f6..97c352b5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / isPlaying diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md index 5c3800aa..db5f5b3c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / originalHeight diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md index 5cf5f71e..30bf73d8 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / originalWidth diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md index 62592191..339200c5 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / source diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md index 0265b4af..c46b641c 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / texture diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md index 5d29ff6f..9ea3f4bd 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / videoElement diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md index 39f6e09a..8cfafce1 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Accessor -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / width diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md index eb471e46..085a4c6d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / background @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts background( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md index e64476ac..5f50f7b4 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / brightnessRange diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md index af49fab9..7a029b5b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / cellColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts cellColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md index 05684d59..32ce5d7f 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / cellColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md index a7e7d3b8..188bac13 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / charColor @@ -17,9 +17,9 @@ lastModified: 2026-07-31 ```ts charColor( - colorOrGray, - g?, - b?, + colorOrGray, + g?, + b?, a?): this; ``` diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md index 8ddb0e0f..a4e6d19b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / charColorMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md index abfe6c5b..fc734eff 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / charRotation diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md index 36360e78..3dc7fd47 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / characters diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md index 6b862311..644ed20a 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / clearConversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md index 6558e415..8c4fc759 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / conversionMode diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md index 8ee5ca0a..083a64d6 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / conversions diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md index 31dd0543..386dbbf7 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / dispose diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md index 557553c5..d0a32624 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / flipX diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md index 57eb8d36..0eaafc3d 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / flipY diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md index deeb8b69..ebf71864 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / invert diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md index 0baf2416..210bb0a2 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / loop diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md index 9afcf54a..947273c3 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / pause diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md index 7b84c4d5..3c200e87 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / play diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md index c6a05041..372265ba 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / speed diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md index b58517ad..9751edb7 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / stop diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md index 52c48839..cc954a0b 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / time diff --git a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md index 8df0baf1..511da6b9 100644 --- a/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md +++ b/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md @@ -8,7 +8,7 @@ api: true owner: TextmodeVideo namespace: media kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [media](../../../index.md) / [TextmodeVideo](../../TextmodeVideo.md) / volume diff --git a/api/textmode.js/namespaces/media/index.md b/api/textmode.js/namespaces/media/index.md index e271327c..ff7b6f4d 100644 --- a/api/textmode.js/namespaces/media/index.md +++ b/api/textmode.js/namespaces/media/index.md @@ -6,7 +6,7 @@ description: All media asset related modules and types. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / media diff --git a/api/textmode.js/namespaces/plugins/index.md b/api/textmode.js/namespaces/plugins/index.md index 05240429..3ebacd41 100644 --- a/api/textmode.js/namespaces/plugins/index.md +++ b/api/textmode.js/namespaces/plugins/index.md @@ -6,7 +6,7 @@ description: Plugin system types for extending textmode.js functionality. category: Namespaces api: true kind: Namespace -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../index.md) / plugins diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md index a4ada97b..414f401b 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: plugins kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md index 36455f1e..5ae0a04b 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: plugins kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md index 1a592822..c58a511c 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true namespace: plugins kind: Interface -lastModified: 2026-07-31 +lastModified: 2026-08-02 isInterface: true --- @@ -18,30 +18,116 @@ isInterface: true Host-provided context passed to plugins when they are installed on a [Textmodifier](../../../classes/Textmodifier.md) instance. -## Properties +## Extensions -| Property | Type | Description | -| ------ | ------ | ------ | -| `asciiFramebuffer` | [`TextmodeFramebuffer`](../../../classes/TextmodeFramebuffer.md) | The framebuffer containing the ASCII representation (from base layer).
This framebuffer only has a single attachment. | -| `canvas` | [`TextmodeCanvasHandle`](TextmodeCanvasHandle.md) | A stable handle for the canvas used by the Textmodifier instance. | -| `drawFramebuffer` | [`TextmodeFramebuffer`](../../../classes/TextmodeFramebuffer.md) | The framebuffer the user draws to with 3 attachments (from base layer). | -| `font` | \| [`TextmodeFont`](../../fonts/classes/TextmodeFont.md) \| [`TextmodeTileset`](../../fonts/classes/TextmodeTileset.md) | The active glyph source used by the Textmodifier instance (from base layer). | -| `glyphAtlas` | [`TextmodeGlyphAtlas`](../../fonts/interfaces/TextmodeGlyphAtlas.md) | Backend-neutral glyph atlas used by the Textmodifier instance (from base layer). | -| `grid` | [`TextmodeGrid`](../../../classes/TextmodeGrid.md) | The grid used by the Textmodifier instance (from base layer). | -| `layerManager` | [`TextmodeLayerManager`](../../layering/classes/TextmodeLayerManager.md) | The layer manager for accessing and managing all layers. | - -## Methods +Add and remove methods on layer and source instances. | Method | Description | | ------ | ------ | | [extendLayer](TextmodePluginContext/methods/extendLayer.md) | Extend TextmodeLayer instances with a new method. The method will be available on all existing and future layer instances. | | [extendSource](TextmodePluginContext/methods/extendSource.md) | Extend TextmodeSource instances with a new method. The method will be available on image, video, texture, and overlay sources. | +| [removeLayerExtension](TextmodePluginContext/methods/removeLayerExtension.md) | Remove a method extension from TextmodeLayer. | +| [removeSourceExtension](TextmodePluginContext/methods/removeSourceExtension.md) | Remove a method extension from TextmodeSource. | + +## Host resources + +Access the renderer, grid, glyph atlas, canvas, framebuffers, and layer manager. + +### asciiFramebuffer + +```ts +asciiFramebuffer: TextmodeFramebuffer; +``` + +The framebuffer containing the ASCII representation (from base layer).
+This framebuffer only has a single attachment. + + +*** + +### canvas + +```ts +canvas: TextmodeCanvasHandle; +``` + +A stable handle for the canvas used by the Textmodifier instance. + + +*** + +### drawFramebuffer + +```ts +drawFramebuffer: TextmodeFramebuffer; +``` + +The framebuffer the user draws to with 3 attachments (from base layer). + + +*** + +### font + +```ts +font: + | TextmodeFont + | TextmodeTileset; +``` + +The active glyph source used by the Textmodifier instance (from base layer). + + +*** + +### glyphAtlas + +```ts +glyphAtlas: TextmodeGlyphAtlas; +``` + +Backend-neutral glyph atlas used by the Textmodifier instance (from base layer). + + +*** + +### grid + +```ts +grid: TextmodeGrid; +``` + +The grid used by the Textmodifier instance (from base layer). + + +*** + +### layerManager + +```ts +layerManager: TextmodeLayerManager; +``` + +The layer manager for accessing and managing all layers. + + +## Layer hooks + +Register callbacks around individual layer renders and disposal. + +| Method | Description | +| ------ | ------ | | [registerLayerDisposedHook](TextmodePluginContext/methods/registerLayerDisposedHook.md) | Register a callback to be invoked when a layer is about to be disposed. | | [registerLayerPostRenderHook](TextmodePluginContext/methods/registerLayerPostRenderHook.md) | Register a callback to be invoked after each layer's render cycle. This happens after the user draw callback but before the ASCII resolve pass. | | [registerLayerPreRenderHook](TextmodePluginContext/methods/registerLayerPreRenderHook.md) | Register a callback to be invoked before each layer's render cycle. This happens after the layer's visibility check but before any drawing operations. Useful for rendering content to the layer's framebuffer before user draw callbacks. | + +## Sketch hooks + +Register callbacks around setup and the sketch draw cycle. + +| Method | Description | +| ------ | ------ | | [registerPostDrawHook](TextmodePluginContext/methods/registerPostDrawHook.md) | Register a callback to be invoked after each draw cycle. Happens outside of the draw framebuffer being bound after the final result is drawn to the screen. | | [registerPostSetupHook](TextmodePluginContext/methods/registerPostSetupHook.md) | Register a callback to be invoked after the user's setup callback completes. This happens after user code in `setup()` has finished executing, but before the loading screen finishes and the main render loop begins. Useful for plugins that need to finalize initialization after user setup. | | [registerPreDrawHook](TextmodePluginContext/methods/registerPreDrawHook.md) | Register a callback to be invoked before each draw cycle. Happens just before any framebuffer | | [registerPreSetupHook](TextmodePluginContext/methods/registerPreSetupHook.md) | Register a callback to be invoked before the user's setup callback runs. This happens after the Textmodifier and all layers are fully initialized, but before user code in `setup()` executes. Useful for plugins that need to prepare resources or state before user setup. | -| [removeLayerExtension](TextmodePluginContext/methods/removeLayerExtension.md) | Remove a method extension from TextmodeLayer. | -| [removeSourceExtension](TextmodePluginContext/methods/removeSourceExtension.md) | Remove a method extension from TextmodeSource. | diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md index 0ed93c8c..67df1a2e 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / extendLayer diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md index ab2e1dd3..9f099aa3 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / extendSource diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md index 843f77b4..ba81bd51 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerLayerDisposedHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md index 7471109c..772b9415 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerLayerPostRenderHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md index dd561297..4c6003cc 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerLayerPreRenderHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md index 3170b8bd..2676c529 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerPostDrawHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md index 35c3ab90..e1214d4b 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerPostSetupHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md index 2e4967a2..324a0de3 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerPreDrawHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md index 97fea677..04a92254 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / registerPreSetupHook diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md index 0af20ff0..fab0a194 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / removeLayerExtension diff --git a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md index 3b642eae..32542306 100644 --- a/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md +++ b/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md @@ -8,7 +8,7 @@ api: true owner: TextmodePluginContext namespace: plugins kind: Method -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../../../index.md) / [plugins](../../../index.md) / [TextmodePluginContext](../../TextmodePluginContext.md) / removeSourceExtension diff --git a/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md b/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md index d22d0e5f..6700936c 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / LayerExtensionImplementation diff --git a/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md b/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md index a3a1c6ae..a2052996 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / LayerLifecycleHook diff --git a/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md b/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md index 875e8fa2..4a8febc2 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / LayerRenderHook diff --git a/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md b/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md index 932d165a..4e79b357 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / SetupLifecycleHook diff --git a/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md b/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md index 57929eb6..d8f7135f 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / SourceExtensionImplementation diff --git a/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md b/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md index bfe8e299..5473c01d 100644 --- a/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md +++ b/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md @@ -7,7 +7,7 @@ category: Type Aliases api: true namespace: plugins kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../../../index.md) / [plugins](../index.md) / TextmodePluginHook diff --git a/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md b/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md index f2fbcaf1..310cb33a 100644 --- a/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md +++ b/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md @@ -6,7 +6,7 @@ description: Options for creating a framebuffer via Textmodifier.createFramebuff category: Type Aliases api: true kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../index.md) / TextmodeFramebufferOptions diff --git a/api/textmode.js/type-aliases/TextmodeOptions.md b/api/textmode.js/type-aliases/TextmodeOptions.md index 86b1afe1..96b7ba3f 100644 --- a/api/textmode.js/type-aliases/TextmodeOptions.md +++ b/api/textmode.js/type-aliases/TextmodeOptions.md @@ -6,7 +6,7 @@ description: Options when creating a Textmodifier instance via textmode.create. category: Type Aliases api: true kind: TypeAlias -lastModified: 2026-07-31 +lastModified: 2026-08-02 --- [textmode.js](../index.md) / TextmodeOptions diff --git a/api/textmode.js/typedoc-sidebar.json b/api/textmode.js/typedoc-sidebar.json index 56982b52..da5950aa 100644 --- a/api/textmode.js/typedoc-sidebar.json +++ b/api/textmode.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Namespaces","collapsed":true,"items":[{"text":"color","link":"/api/textmode.js/namespaces/color/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeColor","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"a","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md"},{"text":"b","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md"},{"text":"g","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md"},{"text":"r","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"normalized","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md"},{"text":"rgb","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md"},{"text":"rgba","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"withAlpha","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeColorMode","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md"},{"text":"TextmodeColorModeState","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md"},{"text":"TextmodeColorTuple","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md"}]}]},{"text":"conversion","link":"/api/textmode.js/namespaces/conversion/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeConversionManager","link":"/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeConversionContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md"},{"text":"TextmodeConversionPassContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md"},{"text":"TextmodeConversionSource","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md"},{"text":"TextmodeConversionStep","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md"},{"text":"TextmodeConversionStrategy","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md"},{"text":"TextmodeColorInput","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md"},{"text":"TextmodeConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md"},{"text":"TextmodeConversionStepOptions","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md"}]}]},{"text":"errors","link":"/api/textmode.js/namespaces/errors/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"TextmodeErrorLevel","link":"/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"ErrorLayerController","link":"/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md"},{"text":"TextmodeError","link":"/api/textmode.js/namespaces/errors/classes/TextmodeError.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"ErrorScreenRendererContext","link":"/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md"},{"text":"TextmodeErrorFormatOptions","link":"/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md"}]}]},{"text":"filters","link":"/api/textmode.js/namespaces/filters/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFilterManager","link":"/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"BuiltInFilterParams","link":"/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md"},{"text":"FilterContext","link":"/api/textmode.js/namespaces/filters/interfaces/FilterContext.md"},{"text":"TextmodeFilterStrategy","link":"/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInFilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md"},{"text":"FilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/FilterName.md"},{"text":"TextmodeFilterUniformDefinitions","link":"/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md"}]}]},{"text":"fonts","link":"/api/textmode.js/namespaces/fonts/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFont","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md"},{"text":"font","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md"}]}]},{"text":"TextmodeTileset","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md"},{"text":"cellHeight","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md"},{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md"},{"text":"columns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md"},{"text":"fontFramebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md"},{"text":"nativeCellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md"},{"text":"rows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"GlyphData","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md"},{"text":"GlyphDimensions","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md"},{"text":"TextmodeGlyphAtlas","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md"},{"text":"TextmodeTilesetOptions","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeGlyph","link":"/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md"}]}]},{"text":"input","link":"/api/textmode.js/namespaces/input/","collapsed":true,"items":[{"text":"Namespaces","collapsed":true,"items":[{"text":"gamepad","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"GamepadAxisEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md"},{"text":"GamepadButtonEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md"},{"text":"GamepadConnectionEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md"},{"text":"GamepadEventMap","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md"},{"text":"TextmodeGamepadButtonSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md"},{"text":"TextmodeGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md"},{"text":"TextmodeGamepadStickSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md"},{"text":"TextmodeStandardGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"GamepadAxisEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md"},{"text":"GamepadButtonEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md"},{"text":"GamepadConnectionEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md"},{"text":"TextmodeStandardAxisName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md"},{"text":"TextmodeStandardButtonName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GAMEPAD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md"}]}]},{"text":"keyboard","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"KeyboardEventData","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md"},{"text":"KeyboardEventMap","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"KeyboardEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"KEYBOARD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md"}]}]},{"text":"mouse","link":"/api/textmode.js/namespaces/input/namespaces/mouse/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"MouseEventData","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md"},{"text":"MouseEventMap","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"MouseEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md"},{"text":"MousePosition","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"MOUSE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md"}]}]},{"text":"touch","link":"/api/textmode.js/namespaces/input/namespaces/touch/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TouchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md"},{"text":"TouchEventMap","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md"},{"text":"TouchLongPressEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md"},{"text":"TouchPinchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md"},{"text":"TouchPosition","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md"},{"text":"TouchRotateEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md"},{"text":"TouchSwipeEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md"},{"text":"TouchTapEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TouchEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md"},{"text":"TouchLongPressHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md"},{"text":"TouchPinchHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md"},{"text":"TouchRotateHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md"},{"text":"TouchSwipeHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md"},{"text":"TouchTapHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GESTURE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md"},{"text":"TOUCH_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"InputEventMap","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md"},{"text":"InputEventName","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventName.md"},{"text":"InputEventOwner","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"INPUT_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md"}]}]},{"text":"layering","link":"/api/textmode.js/namespaces/layering/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"LayerBlendMode","link":"/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeLayer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"asciiFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md"},{"text":"drawFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md"},{"text":"font","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md"},{"text":"grid","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md"},{"text":"texture","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"blendMode","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md"},{"text":"camera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md"},{"text":"createCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md"},{"text":"deletePluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md"},{"text":"draw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md"},{"text":"filter","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md"},{"text":"getPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md"},{"text":"hasPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md"},{"text":"hide","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md"},{"text":"loadFont","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md"},{"text":"loadTileset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md"},{"text":"lookAt","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md"},{"text":"offset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md"},{"text":"opacity","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md"},{"text":"ortho","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md"},{"text":"postDraw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md"},{"text":"resetCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md"},{"text":"rotateZ","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md"},{"text":"setCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md"},{"text":"setPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md"},{"text":"show","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md"},{"text":"useTileColors","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md"}]}]},{"text":"TextmodeLayerManager","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"all","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md"},{"text":"base","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md"},{"text":"filters","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md"},{"text":"resultFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md"},{"text":"clear","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md"},{"text":"move","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md"},{"text":"remove","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md"},{"text":"swap","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeLayerOptions","link":"/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md"}]}]},{"text":"loading","link":"/api/textmode.js/namespaces/loading/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"LoadingLayerController","link":"/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"LoadingScreenOptions","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md"},{"text":"LoadingScreenRendererContext","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LoadingScreenState","link":"/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md"}]}]},{"text":"media","link":"/api/textmode.js/namespaces/media/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeImage","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md"}]}]},{"text":"TextmodeSource","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md"}]}]},{"text":"TextmodeTexture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md"}]}]},{"text":"TextmodeVideo","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"currentTime","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md"},{"text":"duration","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md"},{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md"},{"text":"isPlaying","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md"},{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md"},{"text":"videoElement","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md"},{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md"},{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md"},{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md"},{"text":"loop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md"},{"text":"pause","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md"},{"text":"play","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md"},{"text":"speed","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md"},{"text":"stop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md"},{"text":"time","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md"},{"text":"volume","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md"}]}]}]}]},{"text":"plugins","link":"/api/textmode.js/namespaces/plugins/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeCanvasHandle","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md"},{"text":"TextmodePlugin","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md"},{"text":"TextmodePluginContext","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"extendLayer","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md"},{"text":"extendSource","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md"},{"text":"registerLayerDisposedHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md"},{"text":"registerLayerPostRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md"},{"text":"registerLayerPreRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md"},{"text":"registerPostDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md"},{"text":"registerPostSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md"},{"text":"registerPreDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md"},{"text":"registerPreSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md"},{"text":"removeLayerExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md"},{"text":"removeSourceExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LayerExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md"},{"text":"LayerLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md"},{"text":"LayerRenderHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md"},{"text":"SetupLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md"},{"text":"SourceExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md"},{"text":"TextmodePluginHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md"}]}]}]},{"text":"Enumerations","collapsed":true,"items":[{"text":"ShapeAssemblyMode","link":"/api/textmode.js/enumerations/ShapeAssemblyMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"textmode","link":"/api/textmode.js/classes/textmode.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"version","link":"/api/textmode.js/classes/textmode/accessors/version.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"create","link":"/api/textmode.js/classes/textmode/methods/create.md"},{"text":"setErrorLevel","link":"/api/textmode.js/classes/textmode/methods/setErrorLevel.md"}]}]},{"text":"TextmodeCamera","link":"/api/textmode.js/classes/TextmodeCamera.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"eyeX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md"},{"text":"eyeY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md"},{"text":"eyeZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md"},{"text":"targetX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md"},{"text":"targetY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md"},{"text":"targetZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md"},{"text":"upX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upX.md"},{"text":"upY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upY.md"},{"text":"upZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"copy","link":"/api/textmode.js/classes/TextmodeCamera/methods/copy.md"},{"text":"lookAt","link":"/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md"},{"text":"move","link":"/api/textmode.js/classes/TextmodeCamera/methods/move.md"},{"text":"setPosition","link":"/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md"},{"text":"setUp","link":"/api/textmode.js/classes/TextmodeCamera/methods/setUp.md"}]}]},{"text":"TextmodeFramebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"attachmentCount","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md"},{"text":"framebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md"},{"text":"textures","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"begin","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md"},{"text":"dispose","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md"},{"text":"end","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md"},{"text":"readPixels","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md"},{"text":"resize","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md"}]}]},{"text":"TextmodeGlyphRamp","link":"/api/textmode.js/classes/TextmodeGlyphRamp.md"},{"text":"TextmodeGrid","link":"/api/textmode.js/classes/TextmodeGrid.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellHeight","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md"},{"text":"cols","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cols.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeGrid/accessors/height.md"},{"text":"offsetX","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md"},{"text":"offsetY","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md"},{"text":"rows","link":"/api/textmode.js/classes/TextmodeGrid/accessors/rows.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeGrid/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"reset","link":"/api/textmode.js/classes/TextmodeGrid/methods/reset.md"},{"text":"responsive","link":"/api/textmode.js/classes/TextmodeGrid/methods/responsive.md"}]}]},{"text":"TextmodeRandom","link":"/api/textmode.js/classes/TextmodeRandom.md"},{"text":"TextmodeShader","link":"/api/textmode.js/classes/TextmodeShader.md"},{"text":"TextmodeVector","link":"/api/textmode.js/classes/TextmodeVector.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/classes/TextmodeVector/methods/add.md"},{"text":"copy","link":"/api/textmode.js/classes/TextmodeVector/methods/copy.md"},{"text":"cross","link":"/api/textmode.js/classes/TextmodeVector/methods/cross.md"},{"text":"dist","link":"/api/textmode.js/classes/TextmodeVector/methods/dist.md"},{"text":"div","link":"/api/textmode.js/classes/TextmodeVector/methods/div.md"},{"text":"dot","link":"/api/textmode.js/classes/TextmodeVector/methods/dot.md"},{"text":"heading","link":"/api/textmode.js/classes/TextmodeVector/methods/heading.md"},{"text":"limit","link":"/api/textmode.js/classes/TextmodeVector/methods/limit.md"},{"text":"mag","link":"/api/textmode.js/classes/TextmodeVector/methods/mag.md"},{"text":"magSq","link":"/api/textmode.js/classes/TextmodeVector/methods/magSq.md"},{"text":"mult","link":"/api/textmode.js/classes/TextmodeVector/methods/mult.md"},{"text":"normalize","link":"/api/textmode.js/classes/TextmodeVector/methods/normalize.md"},{"text":"set","link":"/api/textmode.js/classes/TextmodeVector/methods/set.md"},{"text":"setMag","link":"/api/textmode.js/classes/TextmodeVector/methods/setMag.md"},{"text":"sub","link":"/api/textmode.js/classes/TextmodeVector/methods/sub.md"}]}]},{"text":"Textmodifier","link":"/api/textmode.js/classes/Textmodifier.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"BLEND_ADDITIVE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md"},{"text":"BLEND_COLOR_BURN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md"},{"text":"BLEND_COLOR_DODGE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md"},{"text":"BLEND_DARKEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md"},{"text":"BLEND_DIFFERENCE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md"},{"text":"BLEND_EXCLUSION","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md"},{"text":"BLEND_HARD_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md"},{"text":"BLEND_LIGHTEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md"},{"text":"BLEND_MULTIPLY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md"},{"text":"BLEND_NORMAL","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md"},{"text":"BLEND_OVERLAY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md"},{"text":"BLEND_SCREEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md"},{"text":"BLEND_SOFT_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md"},{"text":"BLEND_SUBTRACT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md"},{"text":"displayHeight","link":"/api/textmode.js/classes/Textmodifier/properties/displayHeight.md"},{"text":"displayWidth","link":"/api/textmode.js/classes/Textmodifier/properties/displayWidth.md"},{"text":"gamepads","link":"/api/textmode.js/classes/Textmodifier/properties/gamepads.md"},{"text":"lastKeyPressed","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md"},{"text":"lastKeyReleased","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md"},{"text":"LINE_LOOP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md"},{"text":"LINE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md"},{"text":"LINES","link":"/api/textmode.js/classes/Textmodifier/properties/LINES.md"},{"text":"modifierState","link":"/api/textmode.js/classes/Textmodifier/properties/modifierState.md"},{"text":"mouse","link":"/api/textmode.js/classes/Textmodifier/properties/mouse.md"},{"text":"mouseIsPressed","link":"/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md"},{"text":"movedX","link":"/api/textmode.js/classes/Textmodifier/properties/movedX.md"},{"text":"movedY","link":"/api/textmode.js/classes/Textmodifier/properties/movedY.md"},{"text":"pmouse","link":"/api/textmode.js/classes/Textmodifier/properties/pmouse.md"},{"text":"POINTS","link":"/api/textmode.js/classes/Textmodifier/properties/POINTS.md"},{"text":"pressedKeys","link":"/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md"},{"text":"QUAD_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md"},{"text":"QUADS","link":"/api/textmode.js/classes/Textmodifier/properties/QUADS.md"},{"text":"touches","link":"/api/textmode.js/classes/Textmodifier/properties/touches.md"},{"text":"TRIANGLE_FAN","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md"},{"text":"TRIANGLE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md"},{"text":"TRIANGLES","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md"},{"text":"windowHeight","link":"/api/textmode.js/classes/Textmodifier/properties/windowHeight.md"},{"text":"windowWidth","link":"/api/textmode.js/classes/Textmodifier/properties/windowWidth.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"canvas","link":"/api/textmode.js/classes/Textmodifier/accessors/canvas.md"},{"text":"conversions","link":"/api/textmode.js/classes/Textmodifier/accessors/conversions.md"},{"text":"errors","link":"/api/textmode.js/classes/Textmodifier/accessors/errors.md"},{"text":"filters","link":"/api/textmode.js/classes/Textmodifier/accessors/filters.md"},{"text":"font","link":"/api/textmode.js/classes/Textmodifier/accessors/font.md"},{"text":"frameCount","link":"/api/textmode.js/classes/Textmodifier/accessors/frameCount.md"},{"text":"grid","link":"/api/textmode.js/classes/Textmodifier/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/classes/Textmodifier/accessors/height.md"},{"text":"isDisposed","link":"/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md"},{"text":"isRenderingFrame","link":"/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md"},{"text":"layers","link":"/api/textmode.js/classes/Textmodifier/accessors/layers.md"},{"text":"loading","link":"/api/textmode.js/classes/Textmodifier/accessors/loading.md"},{"text":"millis","link":"/api/textmode.js/classes/Textmodifier/accessors/millis.md"},{"text":"overlay","link":"/api/textmode.js/classes/Textmodifier/accessors/overlay.md"},{"text":"secs","link":"/api/textmode.js/classes/Textmodifier/accessors/secs.md"},{"text":"width","link":"/api/textmode.js/classes/Textmodifier/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"abs","link":"/api/textmode.js/classes/Textmodifier/methods/abs.md"},{"text":"acos","link":"/api/textmode.js/classes/Textmodifier/methods/acos.md"},{"text":"ambientLight","link":"/api/textmode.js/classes/Textmodifier/methods/ambientLight.md"},{"text":"applyMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md"},{"text":"arc","link":"/api/textmode.js/classes/Textmodifier/methods/arc.md"},{"text":"asin","link":"/api/textmode.js/classes/Textmodifier/methods/asin.md"},{"text":"atan","link":"/api/textmode.js/classes/Textmodifier/methods/atan.md"},{"text":"atan2","link":"/api/textmode.js/classes/Textmodifier/methods/atan2.md"},{"text":"background","link":"/api/textmode.js/classes/Textmodifier/methods/background.md"},{"text":"beginShape","link":"/api/textmode.js/classes/Textmodifier/methods/beginShape.md"},{"text":"bezierCurve","link":"/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md"},{"text":"box","link":"/api/textmode.js/classes/Textmodifier/methods/box.md"},{"text":"camera","link":"/api/textmode.js/classes/Textmodifier/methods/camera.md"},{"text":"ceil","link":"/api/textmode.js/classes/Textmodifier/methods/ceil.md"},{"text":"cellColor","link":"/api/textmode.js/classes/Textmodifier/methods/cellColor.md"},{"text":"char","link":"/api/textmode.js/classes/Textmodifier/methods/char.md"},{"text":"charColor","link":"/api/textmode.js/classes/Textmodifier/methods/charColor.md"},{"text":"charRotation","link":"/api/textmode.js/classes/Textmodifier/methods/charRotation.md"},{"text":"clamp","link":"/api/textmode.js/classes/Textmodifier/methods/clamp.md"},{"text":"clear","link":"/api/textmode.js/classes/Textmodifier/methods/clear.md"},{"text":"color","link":"/api/textmode.js/classes/Textmodifier/methods/color.md"},{"text":"colorMode","link":"/api/textmode.js/classes/Textmodifier/methods/colorMode.md"},{"text":"cone","link":"/api/textmode.js/classes/Textmodifier/methods/cone.md"},{"text":"constrain","link":"/api/textmode.js/classes/Textmodifier/methods/constrain.md"},{"text":"cos","link":"/api/textmode.js/classes/Textmodifier/methods/cos.md"},{"text":"createCamera","link":"/api/textmode.js/classes/Textmodifier/methods/createCamera.md"},{"text":"createFilterShader","link":"/api/textmode.js/classes/Textmodifier/methods/createFilterShader.md"},{"text":"createFramebuffer","link":"/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md"},{"text":"createGlyphRamp","link":"/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md"},{"text":"createMaterialShader","link":"/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md"},{"text":"createShader","link":"/api/textmode.js/classes/Textmodifier/methods/createShader.md"},{"text":"createTexture","link":"/api/textmode.js/classes/Textmodifier/methods/createTexture.md"},{"text":"createVector","link":"/api/textmode.js/classes/Textmodifier/methods/createVector.md"},{"text":"cursor","link":"/api/textmode.js/classes/Textmodifier/methods/cursor.md"},{"text":"cylinder","link":"/api/textmode.js/classes/Textmodifier/methods/cylinder.md"},{"text":"degrees","link":"/api/textmode.js/classes/Textmodifier/methods/degrees.md"},{"text":"deltaTime","link":"/api/textmode.js/classes/Textmodifier/methods/deltaTime.md"},{"text":"destroy","link":"/api/textmode.js/classes/Textmodifier/methods/destroy.md"},{"text":"dist","link":"/api/textmode.js/classes/Textmodifier/methods/dist.md"},{"text":"doubleClicked","link":"/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md"},{"text":"doubleTap","link":"/api/textmode.js/classes/Textmodifier/methods/doubleTap.md"},{"text":"draw","link":"/api/textmode.js/classes/Textmodifier/methods/draw.md"},{"text":"ease","link":"/api/textmode.js/classes/Textmodifier/methods/ease.md"},{"text":"ellipse","link":"/api/textmode.js/classes/Textmodifier/methods/ellipse.md"},{"text":"ellipsoid","link":"/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md"},{"text":"endShape","link":"/api/textmode.js/classes/Textmodifier/methods/endShape.md"},{"text":"exitPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md"},{"text":"exp","link":"/api/textmode.js/classes/Textmodifier/methods/exp.md"},{"text":"fill","link":"/api/textmode.js/classes/Textmodifier/methods/fill.md"},{"text":"filter","link":"/api/textmode.js/classes/Textmodifier/methods/filter.md"},{"text":"finalDraw","link":"/api/textmode.js/classes/Textmodifier/methods/finalDraw.md"},{"text":"flipX","link":"/api/textmode.js/classes/Textmodifier/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/classes/Textmodifier/methods/flipY.md"},{"text":"floor","link":"/api/textmode.js/classes/Textmodifier/methods/floor.md"},{"text":"fontSize","link":"/api/textmode.js/classes/Textmodifier/methods/fontSize.md"},{"text":"fract","link":"/api/textmode.js/classes/Textmodifier/methods/fract.md"},{"text":"frameRate","link":"/api/textmode.js/classes/Textmodifier/methods/frameRate.md"},{"text":"gamepad","link":"/api/textmode.js/classes/Textmodifier/methods/gamepad.md"},{"text":"gamepadAxisChanged","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md"},{"text":"gamepadButtonPressed","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md"},{"text":"gamepadButtonReleased","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md"},{"text":"gamepadConnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md"},{"text":"gamepadDisconnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md"},{"text":"image","link":"/api/textmode.js/classes/Textmodifier/methods/image.md"},{"text":"inputGrid","link":"/api/textmode.js/classes/Textmodifier/methods/inputGrid.md"},{"text":"invert","link":"/api/textmode.js/classes/Textmodifier/methods/invert.md"},{"text":"isKeyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md"},{"text":"isLooping","link":"/api/textmode.js/classes/Textmodifier/methods/isLooping.md"},{"text":"keyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/keyPressed.md"},{"text":"keyReleased","link":"/api/textmode.js/classes/Textmodifier/methods/keyReleased.md"},{"text":"keyTyped","link":"/api/textmode.js/classes/Textmodifier/methods/keyTyped.md"},{"text":"lerp","link":"/api/textmode.js/classes/Textmodifier/methods/lerp.md"},{"text":"lightFalloff","link":"/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md"},{"text":"line","link":"/api/textmode.js/classes/Textmodifier/methods/line.md"},{"text":"lineWeight","link":"/api/textmode.js/classes/Textmodifier/methods/lineWeight.md"},{"text":"loadFont","link":"/api/textmode.js/classes/Textmodifier/methods/loadFont.md"},{"text":"loadImage","link":"/api/textmode.js/classes/Textmodifier/methods/loadImage.md"},{"text":"loadTileset","link":"/api/textmode.js/classes/Textmodifier/methods/loadTileset.md"},{"text":"loadVideo","link":"/api/textmode.js/classes/Textmodifier/methods/loadVideo.md"},{"text":"log","link":"/api/textmode.js/classes/Textmodifier/methods/log.md"},{"text":"longPress","link":"/api/textmode.js/classes/Textmodifier/methods/longPress.md"},{"text":"lookAt","link":"/api/textmode.js/classes/Textmodifier/methods/lookAt.md"},{"text":"loop","link":"/api/textmode.js/classes/Textmodifier/methods/loop.md"},{"text":"map","link":"/api/textmode.js/classes/Textmodifier/methods/map.md"},{"text":"max","link":"/api/textmode.js/classes/Textmodifier/methods/max.md"},{"text":"min","link":"/api/textmode.js/classes/Textmodifier/methods/min.md"},{"text":"mouseClicked","link":"/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md"},{"text":"mouseDragged","link":"/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md"},{"text":"mouseMoved","link":"/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md"},{"text":"mousePressed","link":"/api/textmode.js/classes/Textmodifier/methods/mousePressed.md"},{"text":"mouseReleased","link":"/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md"},{"text":"mouseScrolled","link":"/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md"},{"text":"noise","link":"/api/textmode.js/classes/Textmodifier/methods/noise.md"},{"text":"noiseDetail","link":"/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md"},{"text":"noiseSeed","link":"/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md"},{"text":"noLights","link":"/api/textmode.js/classes/Textmodifier/methods/noLights.md"},{"text":"noLoop","link":"/api/textmode.js/classes/Textmodifier/methods/noLoop.md"},{"text":"norm","link":"/api/textmode.js/classes/Textmodifier/methods/norm.md"},{"text":"noTexture","link":"/api/textmode.js/classes/Textmodifier/methods/noTexture.md"},{"text":"off","link":"/api/textmode.js/classes/Textmodifier/methods/off.md"},{"text":"on","link":"/api/textmode.js/classes/Textmodifier/methods/on.md"},{"text":"once","link":"/api/textmode.js/classes/Textmodifier/methods/once.md"},{"text":"ortho","link":"/api/textmode.js/classes/Textmodifier/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/classes/Textmodifier/methods/perspective.md"},{"text":"pinch","link":"/api/textmode.js/classes/Textmodifier/methods/pinch.md"},{"text":"pixelDensity","link":"/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md"},{"text":"point","link":"/api/textmode.js/classes/Textmodifier/methods/point.md"},{"text":"pointLight","link":"/api/textmode.js/classes/Textmodifier/methods/pointLight.md"},{"text":"pop","link":"/api/textmode.js/classes/Textmodifier/methods/pop.md"},{"text":"postDraw","link":"/api/textmode.js/classes/Textmodifier/methods/postDraw.md"},{"text":"pow","link":"/api/textmode.js/classes/Textmodifier/methods/pow.md"},{"text":"print","link":"/api/textmode.js/classes/Textmodifier/methods/print.md"},{"text":"printAlign","link":"/api/textmode.js/classes/Textmodifier/methods/printAlign.md"},{"text":"push","link":"/api/textmode.js/classes/Textmodifier/methods/push.md"},{"text":"radians","link":"/api/textmode.js/classes/Textmodifier/methods/radians.md"},{"text":"random","link":"/api/textmode.js/classes/Textmodifier/methods/random.md"},{"text":"randomGaussian","link":"/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md"},{"text":"randomSeed","link":"/api/textmode.js/classes/Textmodifier/methods/randomSeed.md"},{"text":"randomStream","link":"/api/textmode.js/classes/Textmodifier/methods/randomStream.md"},{"text":"rect","link":"/api/textmode.js/classes/Textmodifier/methods/rect.md"},{"text":"redraw","link":"/api/textmode.js/classes/Textmodifier/methods/redraw.md"},{"text":"requestPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md"},{"text":"resetCamera","link":"/api/textmode.js/classes/Textmodifier/methods/resetCamera.md"},{"text":"resetMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md"},{"text":"resetShader","link":"/api/textmode.js/classes/Textmodifier/methods/resetShader.md"},{"text":"resizeCanvas","link":"/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md"},{"text":"rotate","link":"/api/textmode.js/classes/Textmodifier/methods/rotate.md"},{"text":"rotateGesture","link":"/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md"},{"text":"rotateX","link":"/api/textmode.js/classes/Textmodifier/methods/rotateX.md"},{"text":"rotateY","link":"/api/textmode.js/classes/Textmodifier/methods/rotateY.md"},{"text":"rotateZ","link":"/api/textmode.js/classes/Textmodifier/methods/rotateZ.md"},{"text":"round","link":"/api/textmode.js/classes/Textmodifier/methods/round.md"},{"text":"scale","link":"/api/textmode.js/classes/Textmodifier/methods/scale.md"},{"text":"setCamera","link":"/api/textmode.js/classes/Textmodifier/methods/setCamera.md"},{"text":"setUniform","link":"/api/textmode.js/classes/Textmodifier/methods/setUniform.md"},{"text":"setUniforms","link":"/api/textmode.js/classes/Textmodifier/methods/setUniforms.md"},{"text":"setup","link":"/api/textmode.js/classes/Textmodifier/methods/setup.md"},{"text":"shader","link":"/api/textmode.js/classes/Textmodifier/methods/shader.md"},{"text":"sin","link":"/api/textmode.js/classes/Textmodifier/methods/sin.md"},{"text":"sphere","link":"/api/textmode.js/classes/Textmodifier/methods/sphere.md"},{"text":"sq","link":"/api/textmode.js/classes/Textmodifier/methods/sq.md"},{"text":"sqrt","link":"/api/textmode.js/classes/Textmodifier/methods/sqrt.md"},{"text":"stroke","link":"/api/textmode.js/classes/Textmodifier/methods/stroke.md"},{"text":"swipe","link":"/api/textmode.js/classes/Textmodifier/methods/swipe.md"},{"text":"tan","link":"/api/textmode.js/classes/Textmodifier/methods/tan.md"},{"text":"tap","link":"/api/textmode.js/classes/Textmodifier/methods/tap.md"},{"text":"targetFrameRate","link":"/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md"},{"text":"texture","link":"/api/textmode.js/classes/Textmodifier/methods/texture.md"},{"text":"torus","link":"/api/textmode.js/classes/Textmodifier/methods/torus.md"},{"text":"touchCancelled","link":"/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md"},{"text":"touchEnded","link":"/api/textmode.js/classes/Textmodifier/methods/touchEnded.md"},{"text":"touchMoved","link":"/api/textmode.js/classes/Textmodifier/methods/touchMoved.md"},{"text":"touchStarted","link":"/api/textmode.js/classes/Textmodifier/methods/touchStarted.md"},{"text":"translate","link":"/api/textmode.js/classes/Textmodifier/methods/translate.md"},{"text":"translateX","link":"/api/textmode.js/classes/Textmodifier/methods/translateX.md"},{"text":"translateY","link":"/api/textmode.js/classes/Textmodifier/methods/translateY.md"},{"text":"translateZ","link":"/api/textmode.js/classes/Textmodifier/methods/translateZ.md"},{"text":"triangle","link":"/api/textmode.js/classes/Textmodifier/methods/triangle.md"},{"text":"useTileColors","link":"/api/textmode.js/classes/Textmodifier/methods/useTileColors.md"},{"text":"vertex","link":"/api/textmode.js/classes/Textmodifier/methods/vertex.md"},{"text":"windowResized","link":"/api/textmode.js/classes/Textmodifier/methods/windowResized.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeFramebufferOptions","link":"/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md"},{"text":"TextmodeOptions","link":"/api/textmode.js/type-aliases/TextmodeOptions.md"}]}] \ No newline at end of file +[{"text":"Conversion & filters","collapsed":true,"items":[{"text":"conversion","link":"/api/textmode.js/namespaces/conversion/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeConversionManager","link":"/api/textmode.js/namespaces/conversion/classes/TextmodeConversionManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeConversionContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionContext.md"},{"text":"TextmodeConversionPassContext","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionPassContext.md"},{"text":"TextmodeConversionSource","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionSource.md"},{"text":"TextmodeConversionStep","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStep.md"},{"text":"TextmodeConversionStrategy","link":"/api/textmode.js/namespaces/conversion/interfaces/TextmodeConversionStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/BuiltInConversionMode.md"},{"text":"TextmodeColorInput","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeColorInput.md"},{"text":"TextmodeConversionMode","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionMode.md"},{"text":"TextmodeConversionStepOptions","link":"/api/textmode.js/namespaces/conversion/type-aliases/TextmodeConversionStepOptions.md"}]}]},{"text":"filters","link":"/api/textmode.js/namespaces/filters/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFilterManager","link":"/api/textmode.js/namespaces/filters/classes/TextmodeFilterManager.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"BuiltInFilterParams","link":"/api/textmode.js/namespaces/filters/interfaces/BuiltInFilterParams.md"},{"text":"FilterContext","link":"/api/textmode.js/namespaces/filters/interfaces/FilterContext.md"},{"text":"TextmodeFilterStrategy","link":"/api/textmode.js/namespaces/filters/interfaces/TextmodeFilterStrategy.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"BuiltInFilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/BuiltInFilterName.md"},{"text":"FilterName","link":"/api/textmode.js/namespaces/filters/type-aliases/FilterName.md"},{"text":"TextmodeFilterUniformDefinitions","link":"/api/textmode.js/namespaces/filters/type-aliases/TextmodeFilterUniformDefinitions.md"}]}]}]},{"text":"Core workflow","collapsed":true,"items":[{"text":"textmode","link":"/api/textmode.js/classes/textmode.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"version","link":"/api/textmode.js/classes/textmode/accessors/version.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"create","link":"/api/textmode.js/classes/textmode/methods/create.md"},{"text":"setErrorLevel","link":"/api/textmode.js/classes/textmode/methods/setErrorLevel.md"}]}]},{"text":"Textmodifier","link":"/api/textmode.js/classes/Textmodifier.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"BLEND_ADDITIVE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_ADDITIVE.md"},{"text":"BLEND_COLOR_BURN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_BURN.md"},{"text":"BLEND_COLOR_DODGE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_COLOR_DODGE.md"},{"text":"BLEND_DARKEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DARKEN.md"},{"text":"BLEND_DIFFERENCE","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_DIFFERENCE.md"},{"text":"BLEND_EXCLUSION","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_EXCLUSION.md"},{"text":"BLEND_HARD_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_HARD_LIGHT.md"},{"text":"BLEND_LIGHTEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_LIGHTEN.md"},{"text":"BLEND_MULTIPLY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_MULTIPLY.md"},{"text":"BLEND_NORMAL","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_NORMAL.md"},{"text":"BLEND_OVERLAY","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_OVERLAY.md"},{"text":"BLEND_SCREEN","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SCREEN.md"},{"text":"BLEND_SOFT_LIGHT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SOFT_LIGHT.md"},{"text":"BLEND_SUBTRACT","link":"/api/textmode.js/classes/Textmodifier/properties/BLEND_SUBTRACT.md"},{"text":"displayHeight","link":"/api/textmode.js/classes/Textmodifier/properties/displayHeight.md"},{"text":"displayWidth","link":"/api/textmode.js/classes/Textmodifier/properties/displayWidth.md"},{"text":"gamepads","link":"/api/textmode.js/classes/Textmodifier/properties/gamepads.md"},{"text":"lastKeyPressed","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyPressed.md"},{"text":"lastKeyReleased","link":"/api/textmode.js/classes/Textmodifier/properties/lastKeyReleased.md"},{"text":"LINE_LOOP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_LOOP.md"},{"text":"LINE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/LINE_STRIP.md"},{"text":"LINES","link":"/api/textmode.js/classes/Textmodifier/properties/LINES.md"},{"text":"modifierState","link":"/api/textmode.js/classes/Textmodifier/properties/modifierState.md"},{"text":"mouse","link":"/api/textmode.js/classes/Textmodifier/properties/mouse.md"},{"text":"mouseIsPressed","link":"/api/textmode.js/classes/Textmodifier/properties/mouseIsPressed.md"},{"text":"movedX","link":"/api/textmode.js/classes/Textmodifier/properties/movedX.md"},{"text":"movedY","link":"/api/textmode.js/classes/Textmodifier/properties/movedY.md"},{"text":"pmouse","link":"/api/textmode.js/classes/Textmodifier/properties/pmouse.md"},{"text":"POINTS","link":"/api/textmode.js/classes/Textmodifier/properties/POINTS.md"},{"text":"pressedKeys","link":"/api/textmode.js/classes/Textmodifier/properties/pressedKeys.md"},{"text":"QUAD_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/QUAD_STRIP.md"},{"text":"QUADS","link":"/api/textmode.js/classes/Textmodifier/properties/QUADS.md"},{"text":"touches","link":"/api/textmode.js/classes/Textmodifier/properties/touches.md"},{"text":"TRIANGLE_FAN","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_FAN.md"},{"text":"TRIANGLE_STRIP","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLE_STRIP.md"},{"text":"TRIANGLES","link":"/api/textmode.js/classes/Textmodifier/properties/TRIANGLES.md"},{"text":"windowHeight","link":"/api/textmode.js/classes/Textmodifier/properties/windowHeight.md"},{"text":"windowWidth","link":"/api/textmode.js/classes/Textmodifier/properties/windowWidth.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"canvas","link":"/api/textmode.js/classes/Textmodifier/accessors/canvas.md"},{"text":"conversions","link":"/api/textmode.js/classes/Textmodifier/accessors/conversions.md"},{"text":"errors","link":"/api/textmode.js/classes/Textmodifier/accessors/errors.md"},{"text":"filters","link":"/api/textmode.js/classes/Textmodifier/accessors/filters.md"},{"text":"font","link":"/api/textmode.js/classes/Textmodifier/accessors/font.md"},{"text":"frameCount","link":"/api/textmode.js/classes/Textmodifier/accessors/frameCount.md"},{"text":"grid","link":"/api/textmode.js/classes/Textmodifier/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/classes/Textmodifier/accessors/height.md"},{"text":"isDisposed","link":"/api/textmode.js/classes/Textmodifier/accessors/isDisposed.md"},{"text":"isRenderingFrame","link":"/api/textmode.js/classes/Textmodifier/accessors/isRenderingFrame.md"},{"text":"layers","link":"/api/textmode.js/classes/Textmodifier/accessors/layers.md"},{"text":"loading","link":"/api/textmode.js/classes/Textmodifier/accessors/loading.md"},{"text":"millis","link":"/api/textmode.js/classes/Textmodifier/accessors/millis.md"},{"text":"overlay","link":"/api/textmode.js/classes/Textmodifier/accessors/overlay.md"},{"text":"secs","link":"/api/textmode.js/classes/Textmodifier/accessors/secs.md"},{"text":"width","link":"/api/textmode.js/classes/Textmodifier/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"abs","link":"/api/textmode.js/classes/Textmodifier/methods/abs.md"},{"text":"acos","link":"/api/textmode.js/classes/Textmodifier/methods/acos.md"},{"text":"ambientLight","link":"/api/textmode.js/classes/Textmodifier/methods/ambientLight.md"},{"text":"applyMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/applyMatrix.md"},{"text":"arc","link":"/api/textmode.js/classes/Textmodifier/methods/arc.md"},{"text":"asin","link":"/api/textmode.js/classes/Textmodifier/methods/asin.md"},{"text":"atan","link":"/api/textmode.js/classes/Textmodifier/methods/atan.md"},{"text":"atan2","link":"/api/textmode.js/classes/Textmodifier/methods/atan2.md"},{"text":"background","link":"/api/textmode.js/classes/Textmodifier/methods/background.md"},{"text":"beginShape","link":"/api/textmode.js/classes/Textmodifier/methods/beginShape.md"},{"text":"bezierCurve","link":"/api/textmode.js/classes/Textmodifier/methods/bezierCurve.md"},{"text":"box","link":"/api/textmode.js/classes/Textmodifier/methods/box.md"},{"text":"camera","link":"/api/textmode.js/classes/Textmodifier/methods/camera.md"},{"text":"ceil","link":"/api/textmode.js/classes/Textmodifier/methods/ceil.md"},{"text":"cellColor","link":"/api/textmode.js/classes/Textmodifier/methods/cellColor.md"},{"text":"char","link":"/api/textmode.js/classes/Textmodifier/methods/char.md"},{"text":"charColor","link":"/api/textmode.js/classes/Textmodifier/methods/charColor.md"},{"text":"charRotation","link":"/api/textmode.js/classes/Textmodifier/methods/charRotation.md"},{"text":"clamp","link":"/api/textmode.js/classes/Textmodifier/methods/clamp.md"},{"text":"clear","link":"/api/textmode.js/classes/Textmodifier/methods/clear.md"},{"text":"color","link":"/api/textmode.js/classes/Textmodifier/methods/color.md"},{"text":"colorMode","link":"/api/textmode.js/classes/Textmodifier/methods/colorMode.md"},{"text":"cone","link":"/api/textmode.js/classes/Textmodifier/methods/cone.md"},{"text":"constrain","link":"/api/textmode.js/classes/Textmodifier/methods/constrain.md"},{"text":"cos","link":"/api/textmode.js/classes/Textmodifier/methods/cos.md"},{"text":"createCamera","link":"/api/textmode.js/classes/Textmodifier/methods/createCamera.md"},{"text":"createFramebuffer","link":"/api/textmode.js/classes/Textmodifier/methods/createFramebuffer.md"},{"text":"createGlyphRamp","link":"/api/textmode.js/classes/Textmodifier/methods/createGlyphRamp.md"},{"text":"createMaterialShader","link":"/api/textmode.js/classes/Textmodifier/methods/createMaterialShader.md"},{"text":"createShader","link":"/api/textmode.js/classes/Textmodifier/methods/createShader.md"},{"text":"createTexture","link":"/api/textmode.js/classes/Textmodifier/methods/createTexture.md"},{"text":"createVector","link":"/api/textmode.js/classes/Textmodifier/methods/createVector.md"},{"text":"cursor","link":"/api/textmode.js/classes/Textmodifier/methods/cursor.md"},{"text":"cylinder","link":"/api/textmode.js/classes/Textmodifier/methods/cylinder.md"},{"text":"degrees","link":"/api/textmode.js/classes/Textmodifier/methods/degrees.md"},{"text":"deltaTime","link":"/api/textmode.js/classes/Textmodifier/methods/deltaTime.md"},{"text":"destroy","link":"/api/textmode.js/classes/Textmodifier/methods/destroy.md"},{"text":"dist","link":"/api/textmode.js/classes/Textmodifier/methods/dist.md"},{"text":"doubleClicked","link":"/api/textmode.js/classes/Textmodifier/methods/doubleClicked.md"},{"text":"doubleTap","link":"/api/textmode.js/classes/Textmodifier/methods/doubleTap.md"},{"text":"draw","link":"/api/textmode.js/classes/Textmodifier/methods/draw.md"},{"text":"ease","link":"/api/textmode.js/classes/Textmodifier/methods/ease.md"},{"text":"ellipse","link":"/api/textmode.js/classes/Textmodifier/methods/ellipse.md"},{"text":"ellipsoid","link":"/api/textmode.js/classes/Textmodifier/methods/ellipsoid.md"},{"text":"endShape","link":"/api/textmode.js/classes/Textmodifier/methods/endShape.md"},{"text":"exitPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/exitPointerLock.md"},{"text":"exp","link":"/api/textmode.js/classes/Textmodifier/methods/exp.md"},{"text":"fill","link":"/api/textmode.js/classes/Textmodifier/methods/fill.md"},{"text":"filter","link":"/api/textmode.js/classes/Textmodifier/methods/filter.md"},{"text":"finalDraw","link":"/api/textmode.js/classes/Textmodifier/methods/finalDraw.md"},{"text":"flipX","link":"/api/textmode.js/classes/Textmodifier/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/classes/Textmodifier/methods/flipY.md"},{"text":"floor","link":"/api/textmode.js/classes/Textmodifier/methods/floor.md"},{"text":"fontSize","link":"/api/textmode.js/classes/Textmodifier/methods/fontSize.md"},{"text":"fract","link":"/api/textmode.js/classes/Textmodifier/methods/fract.md"},{"text":"frameRate","link":"/api/textmode.js/classes/Textmodifier/methods/frameRate.md"},{"text":"gamepad","link":"/api/textmode.js/classes/Textmodifier/methods/gamepad.md"},{"text":"gamepadAxisChanged","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadAxisChanged.md"},{"text":"gamepadButtonPressed","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonPressed.md"},{"text":"gamepadButtonReleased","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadButtonReleased.md"},{"text":"gamepadConnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadConnected.md"},{"text":"gamepadDisconnected","link":"/api/textmode.js/classes/Textmodifier/methods/gamepadDisconnected.md"},{"text":"image","link":"/api/textmode.js/classes/Textmodifier/methods/image.md"},{"text":"inputGrid","link":"/api/textmode.js/classes/Textmodifier/methods/inputGrid.md"},{"text":"invert","link":"/api/textmode.js/classes/Textmodifier/methods/invert.md"},{"text":"isKeyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/isKeyPressed.md"},{"text":"isLooping","link":"/api/textmode.js/classes/Textmodifier/methods/isLooping.md"},{"text":"keyPressed","link":"/api/textmode.js/classes/Textmodifier/methods/keyPressed.md"},{"text":"keyReleased","link":"/api/textmode.js/classes/Textmodifier/methods/keyReleased.md"},{"text":"keyTyped","link":"/api/textmode.js/classes/Textmodifier/methods/keyTyped.md"},{"text":"lerp","link":"/api/textmode.js/classes/Textmodifier/methods/lerp.md"},{"text":"lightFalloff","link":"/api/textmode.js/classes/Textmodifier/methods/lightFalloff.md"},{"text":"line","link":"/api/textmode.js/classes/Textmodifier/methods/line.md"},{"text":"lineWeight","link":"/api/textmode.js/classes/Textmodifier/methods/lineWeight.md"},{"text":"loadFont","link":"/api/textmode.js/classes/Textmodifier/methods/loadFont.md"},{"text":"loadImage","link":"/api/textmode.js/classes/Textmodifier/methods/loadImage.md"},{"text":"loadTileset","link":"/api/textmode.js/classes/Textmodifier/methods/loadTileset.md"},{"text":"loadVideo","link":"/api/textmode.js/classes/Textmodifier/methods/loadVideo.md"},{"text":"log","link":"/api/textmode.js/classes/Textmodifier/methods/log.md"},{"text":"longPress","link":"/api/textmode.js/classes/Textmodifier/methods/longPress.md"},{"text":"lookAt","link":"/api/textmode.js/classes/Textmodifier/methods/lookAt.md"},{"text":"loop","link":"/api/textmode.js/classes/Textmodifier/methods/loop.md"},{"text":"map","link":"/api/textmode.js/classes/Textmodifier/methods/map.md"},{"text":"max","link":"/api/textmode.js/classes/Textmodifier/methods/max.md"},{"text":"min","link":"/api/textmode.js/classes/Textmodifier/methods/min.md"},{"text":"mouseClicked","link":"/api/textmode.js/classes/Textmodifier/methods/mouseClicked.md"},{"text":"mouseDragged","link":"/api/textmode.js/classes/Textmodifier/methods/mouseDragged.md"},{"text":"mouseMoved","link":"/api/textmode.js/classes/Textmodifier/methods/mouseMoved.md"},{"text":"mousePressed","link":"/api/textmode.js/classes/Textmodifier/methods/mousePressed.md"},{"text":"mouseReleased","link":"/api/textmode.js/classes/Textmodifier/methods/mouseReleased.md"},{"text":"mouseScrolled","link":"/api/textmode.js/classes/Textmodifier/methods/mouseScrolled.md"},{"text":"noise","link":"/api/textmode.js/classes/Textmodifier/methods/noise.md"},{"text":"noiseDetail","link":"/api/textmode.js/classes/Textmodifier/methods/noiseDetail.md"},{"text":"noiseSeed","link":"/api/textmode.js/classes/Textmodifier/methods/noiseSeed.md"},{"text":"noLights","link":"/api/textmode.js/classes/Textmodifier/methods/noLights.md"},{"text":"noLoop","link":"/api/textmode.js/classes/Textmodifier/methods/noLoop.md"},{"text":"norm","link":"/api/textmode.js/classes/Textmodifier/methods/norm.md"},{"text":"noTexture","link":"/api/textmode.js/classes/Textmodifier/methods/noTexture.md"},{"text":"off","link":"/api/textmode.js/classes/Textmodifier/methods/off.md"},{"text":"on","link":"/api/textmode.js/classes/Textmodifier/methods/on.md"},{"text":"once","link":"/api/textmode.js/classes/Textmodifier/methods/once.md"},{"text":"ortho","link":"/api/textmode.js/classes/Textmodifier/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/classes/Textmodifier/methods/perspective.md"},{"text":"pinch","link":"/api/textmode.js/classes/Textmodifier/methods/pinch.md"},{"text":"pixelDensity","link":"/api/textmode.js/classes/Textmodifier/methods/pixelDensity.md"},{"text":"point","link":"/api/textmode.js/classes/Textmodifier/methods/point.md"},{"text":"pointLight","link":"/api/textmode.js/classes/Textmodifier/methods/pointLight.md"},{"text":"pop","link":"/api/textmode.js/classes/Textmodifier/methods/pop.md"},{"text":"postDraw","link":"/api/textmode.js/classes/Textmodifier/methods/postDraw.md"},{"text":"pow","link":"/api/textmode.js/classes/Textmodifier/methods/pow.md"},{"text":"print","link":"/api/textmode.js/classes/Textmodifier/methods/print.md"},{"text":"printAlign","link":"/api/textmode.js/classes/Textmodifier/methods/printAlign.md"},{"text":"push","link":"/api/textmode.js/classes/Textmodifier/methods/push.md"},{"text":"radians","link":"/api/textmode.js/classes/Textmodifier/methods/radians.md"},{"text":"random","link":"/api/textmode.js/classes/Textmodifier/methods/random.md"},{"text":"randomGaussian","link":"/api/textmode.js/classes/Textmodifier/methods/randomGaussian.md"},{"text":"randomSeed","link":"/api/textmode.js/classes/Textmodifier/methods/randomSeed.md"},{"text":"randomStream","link":"/api/textmode.js/classes/Textmodifier/methods/randomStream.md"},{"text":"rect","link":"/api/textmode.js/classes/Textmodifier/methods/rect.md"},{"text":"redraw","link":"/api/textmode.js/classes/Textmodifier/methods/redraw.md"},{"text":"requestPointerLock","link":"/api/textmode.js/classes/Textmodifier/methods/requestPointerLock.md"},{"text":"resetCamera","link":"/api/textmode.js/classes/Textmodifier/methods/resetCamera.md"},{"text":"resetMatrix","link":"/api/textmode.js/classes/Textmodifier/methods/resetMatrix.md"},{"text":"resetShader","link":"/api/textmode.js/classes/Textmodifier/methods/resetShader.md"},{"text":"resizeCanvas","link":"/api/textmode.js/classes/Textmodifier/methods/resizeCanvas.md"},{"text":"rotate","link":"/api/textmode.js/classes/Textmodifier/methods/rotate.md"},{"text":"rotateGesture","link":"/api/textmode.js/classes/Textmodifier/methods/rotateGesture.md"},{"text":"rotateX","link":"/api/textmode.js/classes/Textmodifier/methods/rotateX.md"},{"text":"rotateY","link":"/api/textmode.js/classes/Textmodifier/methods/rotateY.md"},{"text":"rotateZ","link":"/api/textmode.js/classes/Textmodifier/methods/rotateZ.md"},{"text":"round","link":"/api/textmode.js/classes/Textmodifier/methods/round.md"},{"text":"scale","link":"/api/textmode.js/classes/Textmodifier/methods/scale.md"},{"text":"setCamera","link":"/api/textmode.js/classes/Textmodifier/methods/setCamera.md"},{"text":"setUniform","link":"/api/textmode.js/classes/Textmodifier/methods/setUniform.md"},{"text":"setUniforms","link":"/api/textmode.js/classes/Textmodifier/methods/setUniforms.md"},{"text":"setup","link":"/api/textmode.js/classes/Textmodifier/methods/setup.md"},{"text":"shader","link":"/api/textmode.js/classes/Textmodifier/methods/shader.md"},{"text":"sin","link":"/api/textmode.js/classes/Textmodifier/methods/sin.md"},{"text":"sphere","link":"/api/textmode.js/classes/Textmodifier/methods/sphere.md"},{"text":"sq","link":"/api/textmode.js/classes/Textmodifier/methods/sq.md"},{"text":"sqrt","link":"/api/textmode.js/classes/Textmodifier/methods/sqrt.md"},{"text":"stroke","link":"/api/textmode.js/classes/Textmodifier/methods/stroke.md"},{"text":"swipe","link":"/api/textmode.js/classes/Textmodifier/methods/swipe.md"},{"text":"tan","link":"/api/textmode.js/classes/Textmodifier/methods/tan.md"},{"text":"tap","link":"/api/textmode.js/classes/Textmodifier/methods/tap.md"},{"text":"targetFrameRate","link":"/api/textmode.js/classes/Textmodifier/methods/targetFrameRate.md"},{"text":"texture","link":"/api/textmode.js/classes/Textmodifier/methods/texture.md"},{"text":"torus","link":"/api/textmode.js/classes/Textmodifier/methods/torus.md"},{"text":"touchCancelled","link":"/api/textmode.js/classes/Textmodifier/methods/touchCancelled.md"},{"text":"touchEnded","link":"/api/textmode.js/classes/Textmodifier/methods/touchEnded.md"},{"text":"touchMoved","link":"/api/textmode.js/classes/Textmodifier/methods/touchMoved.md"},{"text":"touchStarted","link":"/api/textmode.js/classes/Textmodifier/methods/touchStarted.md"},{"text":"translate","link":"/api/textmode.js/classes/Textmodifier/methods/translate.md"},{"text":"translateX","link":"/api/textmode.js/classes/Textmodifier/methods/translateX.md"},{"text":"translateY","link":"/api/textmode.js/classes/Textmodifier/methods/translateY.md"},{"text":"translateZ","link":"/api/textmode.js/classes/Textmodifier/methods/translateZ.md"},{"text":"triangle","link":"/api/textmode.js/classes/Textmodifier/methods/triangle.md"},{"text":"useTileColors","link":"/api/textmode.js/classes/Textmodifier/methods/useTileColors.md"},{"text":"vertex","link":"/api/textmode.js/classes/Textmodifier/methods/vertex.md"},{"text":"windowResized","link":"/api/textmode.js/classes/Textmodifier/methods/windowResized.md"}]}]},{"text":"TextmodeOptions","link":"/api/textmode.js/type-aliases/TextmodeOptions.md"}]},{"text":"Creative coding utilities","collapsed":true,"items":[{"text":"TextmodeRandom","link":"/api/textmode.js/classes/TextmodeRandom.md"},{"text":"TextmodeVector","link":"/api/textmode.js/classes/TextmodeVector.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/classes/TextmodeVector/methods/add.md"},{"text":"copy","link":"/api/textmode.js/classes/TextmodeVector/methods/copy.md"},{"text":"cross","link":"/api/textmode.js/classes/TextmodeVector/methods/cross.md"},{"text":"dist","link":"/api/textmode.js/classes/TextmodeVector/methods/dist.md"},{"text":"div","link":"/api/textmode.js/classes/TextmodeVector/methods/div.md"},{"text":"dot","link":"/api/textmode.js/classes/TextmodeVector/methods/dot.md"},{"text":"heading","link":"/api/textmode.js/classes/TextmodeVector/methods/heading.md"},{"text":"limit","link":"/api/textmode.js/classes/TextmodeVector/methods/limit.md"},{"text":"mag","link":"/api/textmode.js/classes/TextmodeVector/methods/mag.md"},{"text":"magSq","link":"/api/textmode.js/classes/TextmodeVector/methods/magSq.md"},{"text":"mult","link":"/api/textmode.js/classes/TextmodeVector/methods/mult.md"},{"text":"normalize","link":"/api/textmode.js/classes/TextmodeVector/methods/normalize.md"},{"text":"set","link":"/api/textmode.js/classes/TextmodeVector/methods/set.md"},{"text":"setMag","link":"/api/textmode.js/classes/TextmodeVector/methods/setMag.md"},{"text":"sub","link":"/api/textmode.js/classes/TextmodeVector/methods/sub.md"}]}]}]},{"text":"Drawing & 3D","collapsed":true,"items":[{"text":"ShapeAssemblyMode","link":"/api/textmode.js/enumerations/ShapeAssemblyMode.md"},{"text":"TextmodeCamera","link":"/api/textmode.js/classes/TextmodeCamera.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"eyeX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeX.md"},{"text":"eyeY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeY.md"},{"text":"eyeZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/eyeZ.md"},{"text":"targetX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetX.md"},{"text":"targetY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetY.md"},{"text":"targetZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/targetZ.md"},{"text":"upX","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upX.md"},{"text":"upY","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upY.md"},{"text":"upZ","link":"/api/textmode.js/classes/TextmodeCamera/accessors/upZ.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"copy","link":"/api/textmode.js/classes/TextmodeCamera/methods/copy.md"},{"text":"lookAt","link":"/api/textmode.js/classes/TextmodeCamera/methods/lookAt.md"},{"text":"move","link":"/api/textmode.js/classes/TextmodeCamera/methods/move.md"},{"text":"setPosition","link":"/api/textmode.js/classes/TextmodeCamera/methods/setPosition.md"},{"text":"setUp","link":"/api/textmode.js/classes/TextmodeCamera/methods/setUp.md"}]}]}]},{"text":"Fonts & media","collapsed":true,"items":[{"text":"fonts","link":"/api/textmode.js/namespaces/fonts/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeFont","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/characters.md"},{"text":"font","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/font.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/maxGlyphDimensions.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeFont/methods/dispose.md"}]}]},{"text":"TextmodeTileset","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellDimensions.md"},{"text":"cellHeight","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/cellWidth.md"},{"text":"characterMap","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characterMap.md"},{"text":"characters","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/characters.md"},{"text":"columns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/columns.md"},{"text":"fontFramebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontFramebuffer.md"},{"text":"fontSize","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/fontSize.md"},{"text":"framebuffer","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/framebuffer.md"},{"text":"maxGlyphDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/maxGlyphDimensions.md"},{"text":"nativeCellDimensions","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/nativeCellDimensions.md"},{"text":"rows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/rows.md"},{"text":"textureColumns","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureColumns.md"},{"text":"textureRows","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/accessors/textureRows.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/fonts/classes/TextmodeTileset/methods/dispose.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"GlyphData","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphData.md"},{"text":"GlyphDimensions","link":"/api/textmode.js/namespaces/fonts/interfaces/GlyphDimensions.md"},{"text":"TextmodeGlyphAtlas","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeGlyphAtlas.md"},{"text":"TextmodeTilesetOptions","link":"/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeGlyph","link":"/api/textmode.js/namespaces/fonts/type-aliases/TextmodeGlyph.md"}]}]},{"text":"media","link":"/api/textmode.js/namespaces/media/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeImage","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage.md","collapsed":true,"items":[{"text":"Character & color mapping","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/background.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charColorMode.md"}]},{"text":"Conversion","collapsed":true,"items":[{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/brightnessRange.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/conversions.md"}]},{"text":"Resource lifecycle","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/dispose.md"}]},{"text":"Source dimensions","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/accessors/width.md"}]},{"text":"Source transforms","collapsed":true,"items":[{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/charRotation.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeImage/methods/invert.md"}]}]},{"text":"TextmodeSource","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource.md","collapsed":true,"items":[{"text":"Character & color mapping","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/background.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charColorMode.md"}]},{"text":"Conversion","collapsed":true,"items":[{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/brightnessRange.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/conversions.md"}]},{"text":"Resource lifecycle","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/dispose.md"}]},{"text":"Source dimensions","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/accessors/width.md"}]},{"text":"Source transforms","collapsed":true,"items":[{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/charRotation.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeSource/methods/invert.md"}]}]},{"text":"TextmodeTexture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture.md","collapsed":true,"items":[{"text":"Character & color mapping","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/background.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charColorMode.md"}]},{"text":"Conversion","collapsed":true,"items":[{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/brightnessRange.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/conversions.md"}]},{"text":"Other","collapsed":true,"items":[{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/source.md"}]},{"text":"Resource lifecycle","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/dispose.md"}]},{"text":"Source dimensions","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/accessors/width.md"}]},{"text":"Source transforms","collapsed":true,"items":[{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/charRotation.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeTexture/methods/invert.md"}]}]},{"text":"TextmodeVideo","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo.md","collapsed":true,"items":[{"text":"Character & color mapping","collapsed":true,"items":[{"text":"background","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/background.md"},{"text":"cellColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColor.md"},{"text":"cellColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/cellColorMode.md"},{"text":"characters","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/characters.md"},{"text":"charColor","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColor.md"},{"text":"charColorMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charColorMode.md"}]},{"text":"Conversion","collapsed":true,"items":[{"text":"brightnessRange","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/brightnessRange.md"},{"text":"clearConversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/clearConversions.md"},{"text":"conversionMode","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversionMode.md"},{"text":"conversions","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/conversions.md"}]},{"text":"Other","collapsed":true,"items":[{"text":"source","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/source.md"}]},{"text":"Playback","collapsed":true,"items":[{"text":"loop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/loop.md"},{"text":"pause","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/pause.md"},{"text":"play","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/play.md"},{"text":"speed","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/speed.md"},{"text":"stop","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/stop.md"},{"text":"time","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/time.md"},{"text":"volume","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/volume.md"}]},{"text":"Playback state","collapsed":true,"items":[{"text":"currentTime","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/currentTime.md"},{"text":"duration","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/duration.md"},{"text":"isPlaying","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/isPlaying.md"},{"text":"videoElement","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/videoElement.md"}]},{"text":"Resource lifecycle","collapsed":true,"items":[{"text":"dispose","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/dispose.md"}]},{"text":"Source dimensions","collapsed":true,"items":[{"text":"height","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/height.md"},{"text":"originalHeight","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalHeight.md"},{"text":"originalWidth","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/originalWidth.md"},{"text":"texture","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/accessors/width.md"}]},{"text":"Source transforms","collapsed":true,"items":[{"text":"charRotation","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/charRotation.md"},{"text":"flipX","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipX.md"},{"text":"flipY","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/flipY.md"},{"text":"invert","link":"/api/textmode.js/namespaces/media/classes/TextmodeVideo/methods/invert.md"}]}]}]}]}]},{"text":"Grid, glyphs & color","collapsed":true,"items":[{"text":"color","link":"/api/textmode.js/namespaces/color/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeColor","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor.md","collapsed":true,"items":[{"text":"Properties","collapsed":true,"items":[{"text":"a","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/a.md"},{"text":"b","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/b.md"},{"text":"g","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/g.md"},{"text":"r","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/properties/r.md"}]},{"text":"Accessors","collapsed":true,"items":[{"text":"normalized","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/normalized.md"},{"text":"rgb","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgb.md"},{"text":"rgba","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/accessors/rgba.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"withAlpha","link":"/api/textmode.js/namespaces/color/classes/TextmodeColor/methods/withAlpha.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TextmodeColorMode","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorMode.md"},{"text":"TextmodeColorModeState","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorModeState.md"},{"text":"TextmodeColorTuple","link":"/api/textmode.js/namespaces/color/type-aliases/TextmodeColorTuple.md"}]}]},{"text":"TextmodeGlyphRamp","link":"/api/textmode.js/classes/TextmodeGlyphRamp.md"},{"text":"TextmodeGrid","link":"/api/textmode.js/classes/TextmodeGrid.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"cellHeight","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellHeight.md"},{"text":"cellWidth","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cellWidth.md"},{"text":"cols","link":"/api/textmode.js/classes/TextmodeGrid/accessors/cols.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeGrid/accessors/height.md"},{"text":"offsetX","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetX.md"},{"text":"offsetY","link":"/api/textmode.js/classes/TextmodeGrid/accessors/offsetY.md"},{"text":"rows","link":"/api/textmode.js/classes/TextmodeGrid/accessors/rows.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeGrid/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"reset","link":"/api/textmode.js/classes/TextmodeGrid/methods/reset.md"},{"text":"responsive","link":"/api/textmode.js/classes/TextmodeGrid/methods/responsive.md"}]}]}]},{"text":"Interaction","collapsed":true,"items":[{"text":"input","link":"/api/textmode.js/namespaces/input/","collapsed":true,"items":[{"text":"Namespaces","collapsed":true,"items":[{"text":"gamepad","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"GamepadAxisEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadAxisEventData.md"},{"text":"GamepadButtonEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadButtonEventData.md"},{"text":"GamepadConnectionEventData","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadConnectionEventData.md"},{"text":"GamepadEventMap","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/GamepadEventMap.md"},{"text":"TextmodeGamepadButtonSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadButtonSnapshot.md"},{"text":"TextmodeGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadSnapshot.md"},{"text":"TextmodeGamepadStickSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeGamepadStickSnapshot.md"},{"text":"TextmodeStandardGamepadSnapshot","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/interfaces/TextmodeStandardGamepadSnapshot.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"GamepadAxisEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadAxisEventHandler.md"},{"text":"GamepadButtonEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadButtonEventHandler.md"},{"text":"GamepadConnectionEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/GamepadConnectionEventHandler.md"},{"text":"TextmodeStandardAxisName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardAxisName.md"},{"text":"TextmodeStandardButtonName","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/type-aliases/TextmodeStandardButtonName.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GAMEPAD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/gamepad/variables/GAMEPAD_EVENT_NAMES.md"}]}]},{"text":"keyboard","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"KeyboardEventData","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventData.md"},{"text":"KeyboardEventMap","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/interfaces/KeyboardEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"KeyboardEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/type-aliases/KeyboardEventHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"KEYBOARD_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/keyboard/variables/KEYBOARD_EVENT_NAMES.md"}]}]},{"text":"mouse","link":"/api/textmode.js/namespaces/input/namespaces/mouse/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"MouseEventData","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventData.md"},{"text":"MouseEventMap","link":"/api/textmode.js/namespaces/input/namespaces/mouse/interfaces/MouseEventMap.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"MouseEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MouseEventHandler.md"},{"text":"MousePosition","link":"/api/textmode.js/namespaces/input/namespaces/mouse/type-aliases/MousePosition.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"MOUSE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/mouse/variables/MOUSE_EVENT_NAMES.md"}]}]},{"text":"touch","link":"/api/textmode.js/namespaces/input/namespaces/touch/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TouchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventData.md"},{"text":"TouchEventMap","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchEventMap.md"},{"text":"TouchLongPressEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchLongPressEventData.md"},{"text":"TouchPinchEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPinchEventData.md"},{"text":"TouchPosition","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchPosition.md"},{"text":"TouchRotateEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchRotateEventData.md"},{"text":"TouchSwipeEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchSwipeEventData.md"},{"text":"TouchTapEventData","link":"/api/textmode.js/namespaces/input/namespaces/touch/interfaces/TouchTapEventData.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"TouchEventHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchEventHandler.md"},{"text":"TouchLongPressHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchLongPressHandler.md"},{"text":"TouchPinchHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchPinchHandler.md"},{"text":"TouchRotateHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchRotateHandler.md"},{"text":"TouchSwipeHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchSwipeHandler.md"},{"text":"TouchTapHandler","link":"/api/textmode.js/namespaces/input/namespaces/touch/type-aliases/TouchTapHandler.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"GESTURE_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/GESTURE_EVENT_NAMES.md"},{"text":"TOUCH_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/namespaces/touch/variables/TOUCH_EVENT_NAMES.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"InputEventMap","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventMap.md"},{"text":"InputEventName","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventName.md"},{"text":"InputEventOwner","link":"/api/textmode.js/namespaces/input/type-aliases/InputEventOwner.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"INPUT_EVENT_NAMES","link":"/api/textmode.js/namespaces/input/variables/INPUT_EVENT_NAMES.md"}]}]}]},{"text":"Layers & GPU rendering","collapsed":true,"items":[{"text":"layering","link":"/api/textmode.js/namespaces/layering/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"LayerBlendMode","link":"/api/textmode.js/namespaces/layering/enumerations/LayerBlendMode.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"TextmodeLayer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer.md","collapsed":true,"items":[{"text":"Cameras & projection","collapsed":true,"items":[{"text":"camera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/camera.md"},{"text":"createCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/createCamera.md"},{"text":"lookAt","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/lookAt.md"},{"text":"ortho","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/ortho.md"},{"text":"perspective","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/perspective.md"},{"text":"resetCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/resetCamera.md"},{"text":"setCamera","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setCamera.md"}]},{"text":"Compositing & visibility","collapsed":true,"items":[{"text":"blendMode","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/blendMode.md"},{"text":"filter","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/filter.md"},{"text":"offset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/offset.md"},{"text":"opacity","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/opacity.md"},{"text":"rotateZ","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/rotateZ.md"}]},{"text":"Grid, fonts & glyphs","collapsed":true,"items":[{"text":"fontSize","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/fontSize.md"},{"text":"loadFont","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadFont.md"},{"text":"loadTileset","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/loadTileset.md"},{"text":"useTileColors","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/useTileColors.md"}]},{"text":"Layer lifecycle","collapsed":true,"items":[{"text":"draw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/draw.md"},{"text":"hide","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hide.md"},{"text":"postDraw","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/postDraw.md"},{"text":"show","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/show.md"}]},{"text":"Plugin state","collapsed":true,"items":[{"text":"deletePluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/deletePluginState.md"},{"text":"getPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/getPluginState.md"},{"text":"hasPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/hasPluginState.md"},{"text":"setPluginState","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/methods/setPluginState.md"}]},{"text":"Render outputs","collapsed":true,"items":[{"text":"asciiFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/asciiFramebuffer.md"},{"text":"drawFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/drawFramebuffer.md"},{"text":"font","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/font.md"},{"text":"grid","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/grid.md"},{"text":"height","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/height.md"},{"text":"texture","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/texture.md"},{"text":"width","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayer/accessors/width.md"}]}]},{"text":"TextmodeLayerManager","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"all","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/all.md"},{"text":"base","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/base.md"},{"text":"filters","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/filters.md"},{"text":"resultFramebuffer","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/accessors/resultFramebuffer.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/add.md"},{"text":"clear","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/clear.md"},{"text":"move","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/move.md"},{"text":"remove","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/remove.md"},{"text":"swap","link":"/api/textmode.js/namespaces/layering/classes/TextmodeLayerManager/methods/swap.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeLayerOptions","link":"/api/textmode.js/namespaces/layering/interfaces/TextmodeLayerOptions.md"}]}]},{"text":"TextmodeFramebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer.md","collapsed":true,"items":[{"text":"Accessors","collapsed":true,"items":[{"text":"attachmentCount","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/attachmentCount.md"},{"text":"framebuffer","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/framebuffer.md"},{"text":"height","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/height.md"},{"text":"textures","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/textures.md"},{"text":"width","link":"/api/textmode.js/classes/TextmodeFramebuffer/accessors/width.md"}]},{"text":"Methods","collapsed":true,"items":[{"text":"begin","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/begin.md"},{"text":"dispose","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/dispose.md"},{"text":"end","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/end.md"},{"text":"readPixels","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/readPixels.md"},{"text":"resize","link":"/api/textmode.js/classes/TextmodeFramebuffer/methods/resize.md"}]}]},{"text":"TextmodeShader","link":"/api/textmode.js/classes/TextmodeShader.md"},{"text":"TextmodeFramebufferOptions","link":"/api/textmode.js/type-aliases/TextmodeFramebufferOptions.md"}]},{"text":"Loading & errors","collapsed":true,"items":[{"text":"errors","link":"/api/textmode.js/namespaces/errors/","collapsed":true,"items":[{"text":"Enumerations","collapsed":true,"items":[{"text":"TextmodeErrorLevel","link":"/api/textmode.js/namespaces/errors/enumerations/TextmodeErrorLevel.md"}]},{"text":"Classes","collapsed":true,"items":[{"text":"ErrorLayerController","link":"/api/textmode.js/namespaces/errors/classes/ErrorLayerController.md"},{"text":"TextmodeError","link":"/api/textmode.js/namespaces/errors/classes/TextmodeError.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"ErrorScreenRendererContext","link":"/api/textmode.js/namespaces/errors/interfaces/ErrorScreenRendererContext.md"},{"text":"TextmodeErrorFormatOptions","link":"/api/textmode.js/namespaces/errors/interfaces/TextmodeErrorFormatOptions.md"}]}]},{"text":"loading","link":"/api/textmode.js/namespaces/loading/","collapsed":true,"items":[{"text":"Classes","collapsed":true,"items":[{"text":"LoadingLayerController","link":"/api/textmode.js/namespaces/loading/classes/LoadingLayerController.md"}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"LoadingScreenOptions","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenOptions.md"},{"text":"LoadingScreenRendererContext","link":"/api/textmode.js/namespaces/loading/interfaces/LoadingScreenRendererContext.md"}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LoadingScreenState","link":"/api/textmode.js/namespaces/loading/type-aliases/LoadingScreenState.md"}]}]}]},{"text":"Plugins","collapsed":true,"items":[{"text":"plugins","link":"/api/textmode.js/namespaces/plugins/","collapsed":true,"items":[{"text":"Interfaces","collapsed":true,"items":[{"text":"TextmodeCanvasHandle","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodeCanvasHandle.md"},{"text":"TextmodePlugin","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePlugin.md"},{"text":"TextmodePluginContext","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext.md","collapsed":true,"items":[{"text":"Extensions","collapsed":true,"items":[{"text":"extendLayer","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendLayer.md"},{"text":"extendSource","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/extendSource.md"},{"text":"removeLayerExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeLayerExtension.md"},{"text":"removeSourceExtension","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/removeSourceExtension.md"}]},{"text":"Layer hooks","collapsed":true,"items":[{"text":"registerLayerDisposedHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerDisposedHook.md"},{"text":"registerLayerPostRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPostRenderHook.md"},{"text":"registerLayerPreRenderHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerLayerPreRenderHook.md"}]},{"text":"Sketch hooks","collapsed":true,"items":[{"text":"registerPostDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostDrawHook.md"},{"text":"registerPostSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPostSetupHook.md"},{"text":"registerPreDrawHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreDrawHook.md"},{"text":"registerPreSetupHook","link":"/api/textmode.js/namespaces/plugins/interfaces/TextmodePluginContext/methods/registerPreSetupHook.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"LayerExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerExtensionImplementation.md"},{"text":"LayerLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerLifecycleHook.md"},{"text":"LayerRenderHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/LayerRenderHook.md"},{"text":"SetupLifecycleHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/SetupLifecycleHook.md"},{"text":"SourceExtensionImplementation","link":"/api/textmode.js/namespaces/plugins/type-aliases/SourceExtensionImplementation.md"},{"text":"TextmodePluginHook","link":"/api/textmode.js/namespaces/plugins/type-aliases/TextmodePluginHook.md"}]}]}]}] \ No newline at end of file diff --git a/api/textmode.synth.js/classes/SynthSource.md b/api/textmode.synth.js/classes/SynthSource.md index cced06f8..41179649 100644 --- a/api/textmode.synth.js/classes/SynthSource.md +++ b/api/textmode.synth.js/classes/SynthSource.md @@ -7,7 +7,7 @@ category: Classes api: true kind: Class ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 hasConstructor: false --- @@ -25,84 +25,135 @@ transform to the chain, which is later compiled into a GLSL shader. -## Methods +## Chain utilities + +Methods for reusing or copying an existing synthesis chain. | Method | Description | | ------ | ------ | -| [charMap](SynthSource/methods/charMap.md) | Map character indices to a specific character set. This is the primary textmode-native way to define which characters to use. | -| [charColor](SynthSource/methods/charColor.md) | Set the character foreground color using a color source chain. | -| [char](SynthSource/methods/char.md) | Set the character indices using a character source chain. The number of characters is determined by `charMap()` if defined, otherwise falls back to the total characters in the layer's font. | -| [cellColor](SynthSource/methods/cellColor.md) | Set the cell background colors using a color source chain. | -| [paint](SynthSource/methods/paint.md) | Set both character foreground and cell background color using the same source chain. This is a convenience method that combines `.charColor()` and `.cellColor()` in one call. | | [clone](SynthSource/methods/clone.md) | Create a deep clone of this SynthSource. Useful when you want to create a modified version of an existing chain without affecting the original. | + +## Color transforms + +Methods that adjust, extract, or remap the colors produced by a source. + +| Method | Description | +| ------ | ------ | +| [b](SynthSource/methods/b.md) | Extract the blue channel as a grayscale value. | | [brightness](SynthSource/methods/brightness.md) | Adjust brightness. | +| [clamp](SynthSource/methods/clamp.md) | Clamp color values to a specified range for stability. | +| [color](SynthSource/methods/color.md) | Multiply all channels by a scalar value (grayscale). | +| [colorama](SynthSource/methods/colorama.md) | Apply colorama effect (hue rotation based on luminance). | | [contrast](SynthSource/methods/contrast.md) | Adjust contrast. | -| [invert](SynthSource/methods/invert.md) | Invert colors. | -| [saturate](SynthSource/methods/saturate.md) | Adjust color saturation. | +| [g](SynthSource/methods/g.md) | Extract the green channel as a grayscale value. | +| [gamma](SynthSource/methods/gamma.md) | Apply gamma correction for nonlinear brightness control. | | [hue](SynthSource/methods/hue.md) | Shift hue. | -| [colorama](SynthSource/methods/colorama.md) | Apply colorama effect (hue rotation based on luminance). | -| [posterize](SynthSource/methods/posterize.md) | Posterize colors to limited palette. | +| [invert](SynthSource/methods/invert.md) | Invert colors. | +| [levels](SynthSource/methods/levels.md) | Adjust input/output levels and gamma for precise tonal control. | | [luma](SynthSource/methods/luma.md) | Apply threshold based on luminance. | -| [thresh](SynthSource/methods/thresh.md) | Apply hard threshold. | -| [color](SynthSource/methods/color.md) | Multiply all channels by a scalar value (grayscale). | +| [posterize](SynthSource/methods/posterize.md) | Posterize colors to limited palette. | | [r](SynthSource/methods/r.md) | Extract the red channel as a grayscale value. | -| [g](SynthSource/methods/g.md) | Extract the green channel as a grayscale value. | -| [b](SynthSource/methods/b.md) | Extract the blue channel as a grayscale value. | +| [saturate](SynthSource/methods/saturate.md) | Adjust color saturation. | | [shift](SynthSource/methods/shift.md) | Shift color channels by adding offset values. | -| [gamma](SynthSource/methods/gamma.md) | Apply gamma correction for nonlinear brightness control. | -| [levels](SynthSource/methods/levels.md) | Adjust input/output levels and gamma for precise tonal control. | -| [clamp](SynthSource/methods/clamp.md) | Clamp color values to a specified range for stability. | -| [seed](SynthSource/methods/seed.md) | Set a seed for deterministic randomness in this source chain. | +| [thresh](SynthSource/methods/thresh.md) | Apply hard threshold. | + +## Combining sources + +Methods that blend, mask, or layer one synth source with another. + +| Method | Description | +| ------ | ------ | | [add](SynthSource/methods/add.md) | Add another source. | -| [sub](SynthSource/methods/sub.md) | Subtract another source. | -| [mult](SynthSource/methods/mult.md) | Multiply with another source. | | [blend](SynthSource/methods/blend.md) | Blend with another source. | +| [burn](SynthSource/methods/burn.md) | Color burn blend with another source. | +| [darken](SynthSource/methods/darken.md) | Darken blend with another source. | | [diff](SynthSource/methods/diff.md) | Difference with another source. | +| [dodge](SynthSource/methods/dodge.md) | Color dodge blend with another source. | +| [hardlight](SynthSource/methods/hardlight.md) | Hard light blend with another source. | | [layer](SynthSource/methods/layer.md) | Layer another source on top. | +| [lighten](SynthSource/methods/lighten.md) | Lighten blend with another source. | | [mask](SynthSource/methods/mask.md) | Mask using another source. | -| [screen](SynthSource/methods/screen.md) | Screen blend with another source. | +| [mult](SynthSource/methods/mult.md) | Multiply with another source. | | [overlay](SynthSource/methods/overlay.md) | Overlay blend with another source. | +| [screen](SynthSource/methods/screen.md) | Screen blend with another source. | | [softlight](SynthSource/methods/softlight.md) | Soft light blend with another source. | -| [hardlight](SynthSource/methods/hardlight.md) | Hard light blend with another source. | -| [dodge](SynthSource/methods/dodge.md) | Color dodge blend with another source. | -| [burn](SynthSource/methods/burn.md) | Color burn blend with another source. | -| [lighten](SynthSource/methods/lighten.md) | Lighten blend with another source. | -| [darken](SynthSource/methods/darken.md) | Darken blend with another source. | +| [sub](SynthSource/methods/sub.md) | Subtract another source. | + +## Coordinate modulation + +Methods that use one source to distort another source's coordinates. + +| Method | Description | +| ------ | ------ | | [modulate](SynthSource/methods/modulate.md) | Modulate coordinates using another source. | -| [modulateScale](SynthSource/methods/modulateScale.md) | Modulate scale using another source. | -| [modulateRotate](SynthSource/methods/modulateRotate.md) | Modulate rotation using another source. | -| [modulatePixelate](SynthSource/methods/modulatePixelate.md) | Modulate pixelation using another source. | +| [modulateHue](SynthSource/methods/modulateHue.md) | Modulate coordinates based on hue differences. | | [modulateKaleid](SynthSource/methods/modulateKaleid.md) | Modulate kaleidoscope using another source. | -| [modulateScrollX](SynthSource/methods/modulateScrollX.md) | Modulate X scroll using another source. | -| [modulateScrollY](SynthSource/methods/modulateScrollY.md) | Modulate Y scroll using another source. | +| [modulatePixelate](SynthSource/methods/modulatePixelate.md) | Modulate pixelation using another source. | | [modulateRepeat](SynthSource/methods/modulateRepeat.md) | Modulate repeat pattern with another source. | | [modulateRepeatX](SynthSource/methods/modulateRepeatX.md) | Modulate X repeat with another source. | | [modulateRepeatY](SynthSource/methods/modulateRepeatY.md) | Modulate Y repeat with another source. | -| [modulateHue](SynthSource/methods/modulateHue.md) | Modulate coordinates based on hue differences. | +| [modulateRotate](SynthSource/methods/modulateRotate.md) | Modulate rotation using another source. | +| [modulateScale](SynthSource/methods/modulateScale.md) | Modulate scale using another source. | +| [modulateScrollX](SynthSource/methods/modulateScrollX.md) | Modulate X scroll using another source. | +| [modulateScrollY](SynthSource/methods/modulateScrollY.md) | Modulate Y scroll using another source. | + +## Coordinate transforms + +Methods that reshape the sampling coordinates before a source is evaluated. + +| Method | Description | +| ------ | ------ | +| [barrel](SynthSource/methods/barrel.md) | Barrel distortion (bulge outward). | +| [fisheye](SynthSource/methods/fisheye.md) | Fisheye lens distortion. | +| [kaleid](SynthSource/methods/kaleid.md) | Apply kaleidoscope effect. | +| [mirror](SynthSource/methods/mirror.md) | Mirror coordinates across X and/or Y axes. | +| [pinch](SynthSource/methods/pinch.md) | Pinch distortion (pull inward). | +| [pixelate](SynthSource/methods/pixelate.md) | Pixelate the output. | +| [polar](SynthSource/methods/polar.md) | Convert coordinates to polar space. | +| [repeat](SynthSource/methods/repeat.md) | Repeat coordinates in both X and Y directions. | +| [repeatX](SynthSource/methods/repeatX.md) | Repeat coordinates in X direction. | +| [repeatY](SynthSource/methods/repeatY.md) | Repeat coordinates in Y direction. | | [rotate](SynthSource/methods/rotate.md) | Rotate coordinates. | | [scale](SynthSource/methods/scale.md) | Scale coordinates. | | [scroll](SynthSource/methods/scroll.md) | Scroll coordinates in both X and Y directions. | | [scrollX](SynthSource/methods/scrollX.md) | Scroll coordinates in X direction. | | [scrollY](SynthSource/methods/scrollY.md) | Scroll coordinates in Y direction. | -| [pixelate](SynthSource/methods/pixelate.md) | Pixelate the output. | -| [repeat](SynthSource/methods/repeat.md) | Repeat coordinates in both X and Y directions. | -| [repeatX](SynthSource/methods/repeatX.md) | Repeat coordinates in X direction. | -| [repeatY](SynthSource/methods/repeatY.md) | Repeat coordinates in Y direction. | -| [kaleid](SynthSource/methods/kaleid.md) | Apply kaleidoscope effect. | -| [polar](SynthSource/methods/polar.md) | Convert coordinates to polar space. | -| [twirl](SynthSource/methods/twirl.md) | Twirl distortion with radial falloff. | -| [swirl](SynthSource/methods/swirl.md) | Swirl distortion around a center. | -| [mirror](SynthSource/methods/mirror.md) | Mirror coordinates across X and/or Y axes. | | [shear](SynthSource/methods/shear.md) | Shear coordinates along X and Y axes. | -| [barrel](SynthSource/methods/barrel.md) | Barrel distortion (bulge outward). | -| [pinch](SynthSource/methods/pinch.md) | Pinch distortion (pull inward). | -| [fisheye](SynthSource/methods/fisheye.md) | Fisheye lens distortion. | -| [osc](SynthSource/methods/osc.md) | Generate oscillating patterns using sine waves. | +| [swirl](SynthSource/methods/swirl.md) | Swirl distortion around a center. | +| [twirl](SynthSource/methods/twirl.md) | Twirl distortion with radial falloff. | + +## Determinism + +Methods that make noise-based source chains reproducible. + +| Method | Description | +| ------ | ------ | +| [seed](SynthSource/methods/seed.md) | Set a seed for deterministic randomness in this source chain. | + +## Output Channels + +Methods that choose characters and route values to character and cell colors. + +| Method | Description | +| ------ | ------ | +| [cellColor](SynthSource/methods/cellColor.md) | Set the cell background colors using a color source chain. | +| [char](SynthSource/methods/char.md) | Set the character indices using a character source chain. The number of characters is determined by `charMap()` if defined, otherwise falls back to the total characters in the layer's font. | +| [charColor](SynthSource/methods/charColor.md) | Set the character foreground color using a color source chain. | +| [charMap](SynthSource/methods/charMap.md) | Map character indices to a specific character set. This is the primary textmode-native way to define which characters to use. | +| [paint](SynthSource/methods/paint.md) | Set both character foreground and cell background color using the same source chain. This is a convenience method that combines `.charColor()` and `.cellColor()` in one call. | + +## Sources & Sampling + +Methods that begin a chain from procedural patterns, feedback, or a sampled source. + +| Method | Description | +| ------ | ------ | +| [gradient](SynthSource/methods/gradient.md) | Generate a rotating radial gradient. | +| [moire](SynthSource/methods/moire.md) | Generate moire interference patterns. | | [noise](SynthSource/methods/noise.md) | Generate Perlin noise patterns. | +| [osc](SynthSource/methods/osc.md) | Generate oscillating patterns using sine waves. | | [plasma](SynthSource/methods/plasma.md) | Generate plasma-like sine field patterns. | -| [moire](SynthSource/methods/moire.md) | Generate moire interference patterns. | -| [voronoi](SynthSource/methods/voronoi.md) | Generate voronoi patterns. | -| [gradient](SynthSource/methods/gradient.md) | Generate a rotating radial gradient. | | [shape](SynthSource/methods/shape.md) | Generate geometric shapes (polygons). | | [solid](SynthSource/methods/solid.md) | Generate a solid grayscale color. | | [src](SynthSource/methods/src.md) | Sample the previous frame for feedback effects. | +| [voronoi](SynthSource/methods/voronoi.md) | Generate voronoi patterns. | diff --git a/api/textmode.synth.js/classes/SynthSource/methods/add.md b/api/textmode.synth.js/classes/SynthSource/methods/add.md index 12fa467e..a820d4b2 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/add.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/add.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / add diff --git a/api/textmode.synth.js/classes/SynthSource/methods/b.md b/api/textmode.synth.js/classes/SynthSource/methods/b.md index 0cb639f0..e4429818 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/b.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/b.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / b diff --git a/api/textmode.synth.js/classes/SynthSource/methods/barrel.md b/api/textmode.synth.js/classes/SynthSource/methods/barrel.md index 71514d76..3b778488 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/barrel.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/barrel.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / barrel diff --git a/api/textmode.synth.js/classes/SynthSource/methods/blend.md b/api/textmode.synth.js/classes/SynthSource/methods/blend.md index 121ed8c8..c4dac8f2 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/blend.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/blend.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / blend diff --git a/api/textmode.synth.js/classes/SynthSource/methods/brightness.md b/api/textmode.synth.js/classes/SynthSource/methods/brightness.md index ae062fca..6d7efe4c 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/brightness.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/brightness.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / brightness diff --git a/api/textmode.synth.js/classes/SynthSource/methods/burn.md b/api/textmode.synth.js/classes/SynthSource/methods/burn.md index 8b4c8409..23a53d7e 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/burn.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/burn.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / burn diff --git a/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md b/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md index a32758e2..54330b03 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / cellColor diff --git a/api/textmode.synth.js/classes/SynthSource/methods/char.md b/api/textmode.synth.js/classes/SynthSource/methods/char.md index fe5a4999..8f562e8f 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/char.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/char.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / char diff --git a/api/textmode.synth.js/classes/SynthSource/methods/charColor.md b/api/textmode.synth.js/classes/SynthSource/methods/charColor.md index bcaab32d..c232d1d6 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/charColor.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/charColor.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / charColor diff --git a/api/textmode.synth.js/classes/SynthSource/methods/charMap.md b/api/textmode.synth.js/classes/SynthSource/methods/charMap.md index c6ea5929..c0029453 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/charMap.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/charMap.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / charMap diff --git a/api/textmode.synth.js/classes/SynthSource/methods/clamp.md b/api/textmode.synth.js/classes/SynthSource/methods/clamp.md index 5663e434..e3a97000 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/clamp.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/clamp.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / clamp diff --git a/api/textmode.synth.js/classes/SynthSource/methods/clone.md b/api/textmode.synth.js/classes/SynthSource/methods/clone.md index 48376df6..f2fcad00 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/clone.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/clone.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / clone diff --git a/api/textmode.synth.js/classes/SynthSource/methods/color.md b/api/textmode.synth.js/classes/SynthSource/methods/color.md index 3eaeb181..5a29c436 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/color.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/color.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / color diff --git a/api/textmode.synth.js/classes/SynthSource/methods/colorama.md b/api/textmode.synth.js/classes/SynthSource/methods/colorama.md index f3073698..a57d9411 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/colorama.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/colorama.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / colorama diff --git a/api/textmode.synth.js/classes/SynthSource/methods/contrast.md b/api/textmode.synth.js/classes/SynthSource/methods/contrast.md index ad531851..51169700 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/contrast.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/contrast.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / contrast diff --git a/api/textmode.synth.js/classes/SynthSource/methods/darken.md b/api/textmode.synth.js/classes/SynthSource/methods/darken.md index 9d0e1079..79ae8f12 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/darken.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/darken.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / darken diff --git a/api/textmode.synth.js/classes/SynthSource/methods/diff.md b/api/textmode.synth.js/classes/SynthSource/methods/diff.md index 9d6ee836..4dc5c3b7 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/diff.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/diff.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / diff diff --git a/api/textmode.synth.js/classes/SynthSource/methods/dodge.md b/api/textmode.synth.js/classes/SynthSource/methods/dodge.md index 0c7571ba..b98db938 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/dodge.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/dodge.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / dodge diff --git a/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md b/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md index 46ab9e5f..4305c462 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / fisheye diff --git a/api/textmode.synth.js/classes/SynthSource/methods/g.md b/api/textmode.synth.js/classes/SynthSource/methods/g.md index 6855119e..a20cbca8 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/g.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/g.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / g diff --git a/api/textmode.synth.js/classes/SynthSource/methods/gamma.md b/api/textmode.synth.js/classes/SynthSource/methods/gamma.md index 9ad83023..1c33c5ea 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/gamma.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/gamma.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / gamma diff --git a/api/textmode.synth.js/classes/SynthSource/methods/gradient.md b/api/textmode.synth.js/classes/SynthSource/methods/gradient.md index a9d13230..f42cc53f 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/gradient.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/gradient.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / gradient diff --git a/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md b/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md index f6db8a78..752861a6 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / hardlight diff --git a/api/textmode.synth.js/classes/SynthSource/methods/hue.md b/api/textmode.synth.js/classes/SynthSource/methods/hue.md index 3bcff4fd..6b507319 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/hue.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/hue.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / hue diff --git a/api/textmode.synth.js/classes/SynthSource/methods/invert.md b/api/textmode.synth.js/classes/SynthSource/methods/invert.md index 752494af..a5728655 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/invert.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/invert.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / invert diff --git a/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md b/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md index 0f68a4f6..d7c33d29 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / kaleid diff --git a/api/textmode.synth.js/classes/SynthSource/methods/layer.md b/api/textmode.synth.js/classes/SynthSource/methods/layer.md index a17caf92..e7e7c54a 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/layer.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/layer.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / layer diff --git a/api/textmode.synth.js/classes/SynthSource/methods/levels.md b/api/textmode.synth.js/classes/SynthSource/methods/levels.md index 4811d4b3..b3fe9810 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/levels.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/levels.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / levels diff --git a/api/textmode.synth.js/classes/SynthSource/methods/lighten.md b/api/textmode.synth.js/classes/SynthSource/methods/lighten.md index c5285069..9820ebe0 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/lighten.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/lighten.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / lighten diff --git a/api/textmode.synth.js/classes/SynthSource/methods/luma.md b/api/textmode.synth.js/classes/SynthSource/methods/luma.md index 3d6ac29b..aa7aab33 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/luma.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/luma.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / luma diff --git a/api/textmode.synth.js/classes/SynthSource/methods/mask.md b/api/textmode.synth.js/classes/SynthSource/methods/mask.md index 6c02ed78..5fefff3c 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/mask.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/mask.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / mask diff --git a/api/textmode.synth.js/classes/SynthSource/methods/mirror.md b/api/textmode.synth.js/classes/SynthSource/methods/mirror.md index 3c54a9f3..01b7e544 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/mirror.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/mirror.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / mirror diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulate.md b/api/textmode.synth.js/classes/SynthSource/methods/modulate.md index 30b08a17..a046c44d 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md index 8b0e3b04..119d39b3 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateHue diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md index b7b542fb..3716d4d7 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateKaleid diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md b/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md index ff98264c..66157379 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulatePixelate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md index b91ea02d..3eaa13dc 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateRepeat diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md index 97dd9f10..7a8a672a 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateRepeatX diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md index ead3ce5c..580ac2ec 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateRepeatY diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md index e5388917..ffedc860 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateRotate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md index 96ec1d82..ff323f91 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateScale diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md index dcc76fb6..5359634c 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateScrollX diff --git a/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md b/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md index 6dedaf55..24de218f 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / modulateScrollY diff --git a/api/textmode.synth.js/classes/SynthSource/methods/moire.md b/api/textmode.synth.js/classes/SynthSource/methods/moire.md index 288e32b0..b6233719 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/moire.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/moire.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / moire diff --git a/api/textmode.synth.js/classes/SynthSource/methods/mult.md b/api/textmode.synth.js/classes/SynthSource/methods/mult.md index 244244f3..be8756a2 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/mult.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/mult.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / mult diff --git a/api/textmode.synth.js/classes/SynthSource/methods/noise.md b/api/textmode.synth.js/classes/SynthSource/methods/noise.md index d14f8429..4f60d0af 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/noise.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/noise.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / noise diff --git a/api/textmode.synth.js/classes/SynthSource/methods/osc.md b/api/textmode.synth.js/classes/SynthSource/methods/osc.md index c2bb7cbe..350ddad5 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/osc.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/osc.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / osc diff --git a/api/textmode.synth.js/classes/SynthSource/methods/overlay.md b/api/textmode.synth.js/classes/SynthSource/methods/overlay.md index 8d62aa86..f0b29463 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/overlay.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/overlay.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / overlay diff --git a/api/textmode.synth.js/classes/SynthSource/methods/paint.md b/api/textmode.synth.js/classes/SynthSource/methods/paint.md index 653d9340..fd5f7324 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/paint.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/paint.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / paint diff --git a/api/textmode.synth.js/classes/SynthSource/methods/pinch.md b/api/textmode.synth.js/classes/SynthSource/methods/pinch.md index c20a3fcb..139ccd4f 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/pinch.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/pinch.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / pinch diff --git a/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md b/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md index 74d9b0cb..97f33bf4 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / pixelate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/plasma.md b/api/textmode.synth.js/classes/SynthSource/methods/plasma.md index e2619f87..5cd3a994 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/plasma.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/plasma.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / plasma diff --git a/api/textmode.synth.js/classes/SynthSource/methods/polar.md b/api/textmode.synth.js/classes/SynthSource/methods/polar.md index 6e3a2869..f773f0db 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/polar.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/polar.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / polar diff --git a/api/textmode.synth.js/classes/SynthSource/methods/posterize.md b/api/textmode.synth.js/classes/SynthSource/methods/posterize.md index 673a4ea4..fff2beaa 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/posterize.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/posterize.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / posterize diff --git a/api/textmode.synth.js/classes/SynthSource/methods/r.md b/api/textmode.synth.js/classes/SynthSource/methods/r.md index 88e53e58..a053cc51 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/r.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/r.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / r diff --git a/api/textmode.synth.js/classes/SynthSource/methods/repeat.md b/api/textmode.synth.js/classes/SynthSource/methods/repeat.md index 52fc1a27..796ba57e 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/repeat.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/repeat.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / repeat diff --git a/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md b/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md index a5239da3..874b96c9 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / repeatX diff --git a/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md b/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md index b4008839..40658eae 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / repeatY diff --git a/api/textmode.synth.js/classes/SynthSource/methods/rotate.md b/api/textmode.synth.js/classes/SynthSource/methods/rotate.md index 54cd7678..c7167dbd 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/rotate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/rotate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / rotate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/saturate.md b/api/textmode.synth.js/classes/SynthSource/methods/saturate.md index 668ef4f7..1820ce5e 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/saturate.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/saturate.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / saturate diff --git a/api/textmode.synth.js/classes/SynthSource/methods/scale.md b/api/textmode.synth.js/classes/SynthSource/methods/scale.md index 9fc9b093..62f79723 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/scale.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/scale.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / scale diff --git a/api/textmode.synth.js/classes/SynthSource/methods/screen.md b/api/textmode.synth.js/classes/SynthSource/methods/screen.md index 30034bab..506c1f54 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/screen.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/screen.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / screen diff --git a/api/textmode.synth.js/classes/SynthSource/methods/scroll.md b/api/textmode.synth.js/classes/SynthSource/methods/scroll.md index 39e02d62..d1a7493b 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/scroll.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/scroll.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / scroll diff --git a/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md b/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md index fdc4b009..b5ea7589 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / scrollX diff --git a/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md b/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md index 565018d0..3d00d703 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / scrollY diff --git a/api/textmode.synth.js/classes/SynthSource/methods/seed.md b/api/textmode.synth.js/classes/SynthSource/methods/seed.md index 1aaa4714..aa156d32 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/seed.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/seed.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / seed diff --git a/api/textmode.synth.js/classes/SynthSource/methods/shape.md b/api/textmode.synth.js/classes/SynthSource/methods/shape.md index 8c576279..e11fb366 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/shape.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/shape.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / shape diff --git a/api/textmode.synth.js/classes/SynthSource/methods/shear.md b/api/textmode.synth.js/classes/SynthSource/methods/shear.md index 7642548f..965bc262 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/shear.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/shear.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / shear diff --git a/api/textmode.synth.js/classes/SynthSource/methods/shift.md b/api/textmode.synth.js/classes/SynthSource/methods/shift.md index f813b559..1d5c29b4 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/shift.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/shift.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / shift diff --git a/api/textmode.synth.js/classes/SynthSource/methods/softlight.md b/api/textmode.synth.js/classes/SynthSource/methods/softlight.md index 906ceaec..0947f404 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/softlight.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/softlight.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / softlight diff --git a/api/textmode.synth.js/classes/SynthSource/methods/solid.md b/api/textmode.synth.js/classes/SynthSource/methods/solid.md index 031679c2..861ac414 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/solid.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/solid.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / solid diff --git a/api/textmode.synth.js/classes/SynthSource/methods/src.md b/api/textmode.synth.js/classes/SynthSource/methods/src.md index 7ecf0f09..1d0e1e0f 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/src.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/src.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / src diff --git a/api/textmode.synth.js/classes/SynthSource/methods/sub.md b/api/textmode.synth.js/classes/SynthSource/methods/sub.md index 0a29d9d4..69cb58dd 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/sub.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/sub.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / sub diff --git a/api/textmode.synth.js/classes/SynthSource/methods/swirl.md b/api/textmode.synth.js/classes/SynthSource/methods/swirl.md index 0ed54fd9..6827a163 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/swirl.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/swirl.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / swirl diff --git a/api/textmode.synth.js/classes/SynthSource/methods/thresh.md b/api/textmode.synth.js/classes/SynthSource/methods/thresh.md index bdea0393..5d18896d 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/thresh.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/thresh.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / thresh diff --git a/api/textmode.synth.js/classes/SynthSource/methods/twirl.md b/api/textmode.synth.js/classes/SynthSource/methods/twirl.md index 817f5b42..6db4ccfb 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/twirl.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/twirl.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / twirl diff --git a/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md b/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md index 94083ac7..e12e1f4e 100644 --- a/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md +++ b/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md @@ -8,7 +8,7 @@ api: true owner: SynthSource kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [SynthSource](../../SynthSource.md) / voronoi diff --git a/api/textmode.synth.js/functions/cellColor.md b/api/textmode.synth.js/functions/cellColor.md index 66dcb483..97d683c1 100644 --- a/api/textmode.synth.js/functions/cellColor.md +++ b/api/textmode.synth.js/functions/cellColor.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / cellColor diff --git a/api/textmode.synth.js/functions/char.md b/api/textmode.synth.js/functions/char.md index 4370206f..b258cc5c 100644 --- a/api/textmode.synth.js/functions/char.md +++ b/api/textmode.synth.js/functions/char.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / char diff --git a/api/textmode.synth.js/functions/charColor.md b/api/textmode.synth.js/functions/charColor.md index 31ebe722..313ce9ae 100644 --- a/api/textmode.synth.js/functions/charColor.md +++ b/api/textmode.synth.js/functions/charColor.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / charColor diff --git a/api/textmode.synth.js/functions/gradient.md b/api/textmode.synth.js/functions/gradient.md index f17ddb48..8f8597bb 100644 --- a/api/textmode.synth.js/functions/gradient.md +++ b/api/textmode.synth.js/functions/gradient.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / gradient diff --git a/api/textmode.synth.js/functions/moire.md b/api/textmode.synth.js/functions/moire.md index 01eac088..b44fdb05 100644 --- a/api/textmode.synth.js/functions/moire.md +++ b/api/textmode.synth.js/functions/moire.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / moire diff --git a/api/textmode.synth.js/functions/noise.md b/api/textmode.synth.js/functions/noise.md index 9d23645e..070585bc 100644 --- a/api/textmode.synth.js/functions/noise.md +++ b/api/textmode.synth.js/functions/noise.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / noise diff --git a/api/textmode.synth.js/functions/osc.md b/api/textmode.synth.js/functions/osc.md index 6e13a1c0..f28bcf53 100644 --- a/api/textmode.synth.js/functions/osc.md +++ b/api/textmode.synth.js/functions/osc.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / osc diff --git a/api/textmode.synth.js/functions/paint.md b/api/textmode.synth.js/functions/paint.md index bb4b409d..222ed569 100644 --- a/api/textmode.synth.js/functions/paint.md +++ b/api/textmode.synth.js/functions/paint.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / paint diff --git a/api/textmode.synth.js/functions/plasma.md b/api/textmode.synth.js/functions/plasma.md index 2f731f5e..6d23c2bc 100644 --- a/api/textmode.synth.js/functions/plasma.md +++ b/api/textmode.synth.js/functions/plasma.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / plasma diff --git a/api/textmode.synth.js/functions/setGlobalErrorCallback.md b/api/textmode.synth.js/functions/setGlobalErrorCallback.md index a98b98af..7674c38e 100644 --- a/api/textmode.synth.js/functions/setGlobalErrorCallback.md +++ b/api/textmode.synth.js/functions/setGlobalErrorCallback.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / setGlobalErrorCallback diff --git a/api/textmode.synth.js/functions/shape.md b/api/textmode.synth.js/functions/shape.md index c9634590..b85268b2 100644 --- a/api/textmode.synth.js/functions/shape.md +++ b/api/textmode.synth.js/functions/shape.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / shape diff --git a/api/textmode.synth.js/functions/solid.md b/api/textmode.synth.js/functions/solid.md index 854a39b0..dec2fa46 100644 --- a/api/textmode.synth.js/functions/solid.md +++ b/api/textmode.synth.js/functions/solid.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / solid diff --git a/api/textmode.synth.js/functions/src.md b/api/textmode.synth.js/functions/src.md index 169ee3b8..a45a3db6 100644 --- a/api/textmode.synth.js/functions/src.md +++ b/api/textmode.synth.js/functions/src.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / src diff --git a/api/textmode.synth.js/functions/voronoi.md b/api/textmode.synth.js/functions/voronoi.md index 0dde2274..5b6efbd1 100644 --- a/api/textmode.synth.js/functions/voronoi.md +++ b/api/textmode.synth.js/functions/voronoi.md @@ -7,7 +7,7 @@ category: Functions api: true kind: Function ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / voronoi diff --git a/api/textmode.synth.js/index.md b/api/textmode.synth.js/index.md index b07841a6..07cd054c 100644 --- a/api/textmode.synth.js/index.md +++ b/api/textmode.synth.js/index.md @@ -7,63 +7,98 @@ category: API Reference api: true kind: Project ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- # textmode.synth.js -A derivative work of [hydra-synth](https://github.com/hydra-synth/hydra-synth) by [Olivia Jack](https://github.com/ojack), -adapted for the [textmode.js](https://github.com/humanbydefinition/textmode.js) ecosystem, providing -a visual synthesis system for procedural generation of characters, colors, -and visual effects through method chaining. +Create shader-backed, live-coded textmode scenes by composing generators and +transforms into a [SynthSource](classes/SynthSource.md) chain. + +## Sketch workflow + +1. Add [SynthPlugin](variables/SynthPlugin.md) to the sketch's plugins. +2. Start a chain with a source generator such as [noise](functions/noise.md) or [osc](functions/osc.md). +3. Shape it with coordinate, color, combination, and modulation transforms. +4. Route the result to character, foreground-color, and cell-color channels + with [char](functions/char.md), [charColor](functions/charColor.md), [cellColor](functions/cellColor.md), and [paint](functions/paint.md). +5. Apply the completed chain with `t.synth(source)`. + +Use [src](functions/src.md) for feedback, layer, image, or video sampling. Parameters +accept values, callbacks that receive [SynthContext](interfaces/SynthContext.md), or modulated +arrays for time-based motion. + +## Origins + +textmode.synth.js adapts the compositional approach of +[hydra-synth](https://github.com/hydra-synth/hydra-synth) by +[Olivia Jack](https://github.com/ojack) for the +[textmode.js](https://github.com/humanbydefinition/textmode.js) ecosystem. ## Example -## Classes +## Live-Coding Errors -| Class | Description | -| ------ | ------ | -| [SynthSource](classes/SynthSource.md) | A chainable synthesis source that accumulates transforms to be compiled into a shader. | - -## Interfaces +Hooks for reporting invalid or failed dynamic parameter evaluation without stopping rendering. -| Interface | Description | +| Name | Description | | ------ | ------ | -| [SynthContext](interfaces/SynthContext.md) | Context passed to dynamic parameter functions during rendering. | -| [ModulatedArray](interfaces/ModulatedArray.md) | Extended array interface with modulation methods. | +| [DynamicErrorCallback](type-aliases/DynamicErrorCallback.md) | Callback signature for dynamic parameter evaluation errors. Live coding environments can use this to display errors without interrupting rendering. | +| [setGlobalErrorCallback](functions/setGlobalErrorCallback.md) | Set a global error callback for dynamic parameter evaluation errors. | -## Type Aliases +## Output Channels -| Type Alias | Description | +Functions that route synthesized values to characters, foreground colors, and cell colors. + +| Function | Description | | ------ | ------ | -| [SynthParameterValue](type-aliases/SynthParameterValue.md) | Dynamic parameter value types supported by the synth system. | -| [EasingFunction](type-aliases/EasingFunction.md) | Easing functions from https://gist.github.com/gre/1650294 | -| [DynamicErrorCallback](type-aliases/DynamicErrorCallback.md) | Callback signature for dynamic parameter evaluation errors. Live coding environments can use this to display errors without interrupting rendering. | +| [cellColor](functions/cellColor.md) | Create a synth source with cell background color defined. | +| [char](functions/char.md) | Create a character source from any color/pattern source. | +| [charColor](functions/charColor.md) | Create a synth source with character foreground color defined. | +| [paint](functions/paint.md) | Create a synth source with both character and cell colors defined. | -## Variables +## Parameter Modulation -| Variable | Description | +Values, callbacks, context, easing, and arrays for time-varying synth parameters. + +| Name | Description | | ------ | ------ | -| [SynthPlugin](variables/SynthPlugin.md) | The `textmode.synth.js` plugin to install. | +| [ModulatedArray](interfaces/ModulatedArray.md) | Extended array interface with modulation methods. | +| [SynthContext](interfaces/SynthContext.md) | Context passed to dynamic parameter functions during rendering. | +| [EasingFunction](type-aliases/EasingFunction.md) | Easing functions from https://gist.github.com/gre/1650294 | +| [SynthParameterValue](type-aliases/SynthParameterValue.md) | Dynamic parameter value types supported by the synth system. | | [EASING\_FUNCTIONS](variables/EASING_FUNCTIONS.md) | Easing functions from https://gist.github.com/gre/1650294 | -## Functions +## Sources & Sampling + +Functions that start a chain from procedural patterns, feedback, layers, or media. | Function | Description | | ------ | ------ | -| [cellColor](functions/cellColor.md) | Create a synth source with cell background color defined. | -| [char](functions/char.md) | Create a character source from any color/pattern source. | -| [charColor](functions/charColor.md) | Create a synth source with character foreground color defined. | | [gradient](functions/gradient.md) | Generate a rotating radial gradient. | -| [noise](functions/noise.md) | Generate Perlin noise patterns. | -| [plasma](functions/plasma.md) | Generate plasma-like sine field patterns. | | [moire](functions/moire.md) | Generate moire interference patterns. | +| [noise](functions/noise.md) | Generate Perlin noise patterns. | | [osc](functions/osc.md) | Generate oscillating patterns using sine waves. | -| [paint](functions/paint.md) | Create a synth source with both character and cell colors defined. | +| [plasma](functions/plasma.md) | Generate plasma-like sine field patterns. | | [shape](functions/shape.md) | Generate geometric shapes (polygons). | | [solid](functions/solid.md) | Generate a solid grayscale color. | | [src](functions/src.md) | Sample a source for synth compositions. | | [voronoi](functions/voronoi.md) | Generate voronoi patterns. | -| [setGlobalErrorCallback](functions/setGlobalErrorCallback.md) | Set a global error callback for dynamic parameter evaluation errors. | + +## Synthesis Chains + +The chainable source object that records transforms for shader compilation. + +| Class | Description | +| ------ | ------ | +| [SynthSource](classes/SynthSource.md) | A chainable synthesis source that accumulates transforms to be compiled into a shader. | + +## Workflow + +The plugin that enables synthesis on textmode.js layers. + +| Variable | Description | +| ------ | ------ | +| [SynthPlugin](variables/SynthPlugin.md) | The `textmode.synth.js` plugin to install. | diff --git a/api/textmode.synth.js/interfaces/ModulatedArray.md b/api/textmode.synth.js/interfaces/ModulatedArray.md index ace240da..fd76ad81 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -39,8 +39,8 @@ manually tracking time or state. | Method | Description | | ------ | ------ | -| [fast](ModulatedArray/methods/fast.md) | Set speed multiplier for array cycling. | -| [smooth](ModulatedArray/methods/smooth.md) | Enable smooth interpolation between array values. | | [ease](ModulatedArray/methods/ease.md) | Apply easing function to interpolation between array values. | -| [offset](ModulatedArray/methods/offset.md) | Set time offset for array cycling. | +| [fast](ModulatedArray/methods/fast.md) | Set speed multiplier for array cycling. | | [fit](ModulatedArray/methods/fit.md) | Fit (remap) array values to a new range. | +| [offset](ModulatedArray/methods/offset.md) | Set time offset for array cycling. | +| [smooth](ModulatedArray/methods/smooth.md) | Enable smooth interpolation between array values. | diff --git a/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md b/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md index 630926d4..a2f2773a 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md @@ -8,7 +8,7 @@ api: true owner: ModulatedArray kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [ModulatedArray](../../ModulatedArray.md) / ease @@ -46,3 +46,8 @@ The array for chaining +## Overrides + +```ts +Array.ease +``` diff --git a/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md b/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md index 55ad33b5..cfa8c893 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md @@ -8,7 +8,7 @@ api: true owner: ModulatedArray kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [ModulatedArray](../../ModulatedArray.md) / fast @@ -40,3 +40,8 @@ The array for chaining +## Overrides + +```ts +Array.fast +``` diff --git a/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md b/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md index f90d860f..38be17d6 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md @@ -8,7 +8,7 @@ api: true owner: ModulatedArray kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [ModulatedArray](../../ModulatedArray.md) / fit @@ -45,3 +45,8 @@ A new ModulatedArray with remapped values +## Overrides + +```ts +Array.fit +``` diff --git a/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md b/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md index 6b0257b8..77becdb2 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md @@ -8,7 +8,7 @@ api: true owner: ModulatedArray kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [ModulatedArray](../../ModulatedArray.md) / offset @@ -44,3 +44,8 @@ The array for chaining +## Overrides + +```ts +Array.offset +``` diff --git a/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md b/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md index e20dace4..1568fe36 100644 --- a/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md +++ b/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md @@ -8,7 +8,7 @@ api: true owner: ModulatedArray kind: Method ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../../../index.md) / [ModulatedArray](../../ModulatedArray.md) / smooth @@ -41,3 +41,8 @@ The array for chaining +## Overrides + +```ts +Array.smooth +``` diff --git a/api/textmode.synth.js/interfaces/SynthContext.md b/api/textmode.synth.js/interfaces/SynthContext.md index 03202355..86c98859 100644 --- a/api/textmode.synth.js/interfaces/SynthContext.md +++ b/api/textmode.synth.js/interfaces/SynthContext.md @@ -7,7 +7,7 @@ category: Interfaces api: true kind: Interface ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 isInterface: true --- @@ -25,11 +25,11 @@ Context passed to dynamic parameter functions during rendering. | Property | Type | Description | | ------ | ------ | ------ | -| `time` | `number` | Current time in seconds | +| `bpm` | `number` | Current BPM (beats per minute) for array modulation timing | +| `cols` | `number` | Grid columns | | `frameCount` | `number` | Current frame count | -| `width` | `number` | Grid width in pixels | | `height` | `number` | Grid height in pixels | -| `cols` | `number` | Grid columns | -| `rows` | `number` | Grid rows | -| `bpm` | `number` | Current BPM (beats per minute) for array modulation timing | | `onError?` | (`error`, `uniformName`) => `void` | Optional callback for handling dynamic parameter evaluation errors | +| `rows` | `number` | Grid rows | +| `time` | `number` | Current time in seconds | +| `width` | `number` | Grid width in pixels | diff --git a/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md b/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md index 56d63dfd..7da76202 100644 --- a/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md +++ b/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / DynamicErrorCallback diff --git a/api/textmode.synth.js/type-aliases/EasingFunction.md b/api/textmode.synth.js/type-aliases/EasingFunction.md index 4182bbc9..8d2d5115 100644 --- a/api/textmode.synth.js/type-aliases/EasingFunction.md +++ b/api/textmode.synth.js/type-aliases/EasingFunction.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / EasingFunction diff --git a/api/textmode.synth.js/type-aliases/SynthParameterValue.md b/api/textmode.synth.js/type-aliases/SynthParameterValue.md index 1f9c5695..4acbb077 100644 --- a/api/textmode.synth.js/type-aliases/SynthParameterValue.md +++ b/api/textmode.synth.js/type-aliases/SynthParameterValue.md @@ -7,7 +7,7 @@ category: Type Aliases api: true kind: TypeAlias ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / SynthParameterValue diff --git a/api/textmode.synth.js/typedoc-sidebar.json b/api/textmode.synth.js/typedoc-sidebar.json index 0e65dd81..54f65318 100644 --- a/api/textmode.synth.js/typedoc-sidebar.json +++ b/api/textmode.synth.js/typedoc-sidebar.json @@ -1 +1 @@ -[{"text":"Classes","collapsed":true,"items":[{"text":"SynthSource","link":"/api/textmode.synth.js/classes/SynthSource.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"charMap","link":"/api/textmode.synth.js/classes/SynthSource/methods/charMap.md"},{"text":"charColor","link":"/api/textmode.synth.js/classes/SynthSource/methods/charColor.md"},{"text":"char","link":"/api/textmode.synth.js/classes/SynthSource/methods/char.md"},{"text":"cellColor","link":"/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md"},{"text":"paint","link":"/api/textmode.synth.js/classes/SynthSource/methods/paint.md"},{"text":"clone","link":"/api/textmode.synth.js/classes/SynthSource/methods/clone.md"},{"text":"brightness","link":"/api/textmode.synth.js/classes/SynthSource/methods/brightness.md"},{"text":"contrast","link":"/api/textmode.synth.js/classes/SynthSource/methods/contrast.md"},{"text":"invert","link":"/api/textmode.synth.js/classes/SynthSource/methods/invert.md"},{"text":"saturate","link":"/api/textmode.synth.js/classes/SynthSource/methods/saturate.md"},{"text":"hue","link":"/api/textmode.synth.js/classes/SynthSource/methods/hue.md"},{"text":"colorama","link":"/api/textmode.synth.js/classes/SynthSource/methods/colorama.md"},{"text":"posterize","link":"/api/textmode.synth.js/classes/SynthSource/methods/posterize.md"},{"text":"luma","link":"/api/textmode.synth.js/classes/SynthSource/methods/luma.md"},{"text":"thresh","link":"/api/textmode.synth.js/classes/SynthSource/methods/thresh.md"},{"text":"color","link":"/api/textmode.synth.js/classes/SynthSource/methods/color.md"},{"text":"r","link":"/api/textmode.synth.js/classes/SynthSource/methods/r.md"},{"text":"g","link":"/api/textmode.synth.js/classes/SynthSource/methods/g.md"},{"text":"b","link":"/api/textmode.synth.js/classes/SynthSource/methods/b.md"},{"text":"shift","link":"/api/textmode.synth.js/classes/SynthSource/methods/shift.md"},{"text":"gamma","link":"/api/textmode.synth.js/classes/SynthSource/methods/gamma.md"},{"text":"levels","link":"/api/textmode.synth.js/classes/SynthSource/methods/levels.md"},{"text":"clamp","link":"/api/textmode.synth.js/classes/SynthSource/methods/clamp.md"},{"text":"seed","link":"/api/textmode.synth.js/classes/SynthSource/methods/seed.md"},{"text":"add","link":"/api/textmode.synth.js/classes/SynthSource/methods/add.md"},{"text":"sub","link":"/api/textmode.synth.js/classes/SynthSource/methods/sub.md"},{"text":"mult","link":"/api/textmode.synth.js/classes/SynthSource/methods/mult.md"},{"text":"blend","link":"/api/textmode.synth.js/classes/SynthSource/methods/blend.md"},{"text":"diff","link":"/api/textmode.synth.js/classes/SynthSource/methods/diff.md"},{"text":"layer","link":"/api/textmode.synth.js/classes/SynthSource/methods/layer.md"},{"text":"mask","link":"/api/textmode.synth.js/classes/SynthSource/methods/mask.md"},{"text":"screen","link":"/api/textmode.synth.js/classes/SynthSource/methods/screen.md"},{"text":"overlay","link":"/api/textmode.synth.js/classes/SynthSource/methods/overlay.md"},{"text":"softlight","link":"/api/textmode.synth.js/classes/SynthSource/methods/softlight.md"},{"text":"hardlight","link":"/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md"},{"text":"dodge","link":"/api/textmode.synth.js/classes/SynthSource/methods/dodge.md"},{"text":"burn","link":"/api/textmode.synth.js/classes/SynthSource/methods/burn.md"},{"text":"lighten","link":"/api/textmode.synth.js/classes/SynthSource/methods/lighten.md"},{"text":"darken","link":"/api/textmode.synth.js/classes/SynthSource/methods/darken.md"},{"text":"modulate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulate.md"},{"text":"modulateScale","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md"},{"text":"modulateRotate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md"},{"text":"modulatePixelate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md"},{"text":"modulateKaleid","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md"},{"text":"modulateScrollX","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md"},{"text":"modulateScrollY","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md"},{"text":"modulateRepeat","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md"},{"text":"modulateRepeatX","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md"},{"text":"modulateRepeatY","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md"},{"text":"modulateHue","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md"},{"text":"rotate","link":"/api/textmode.synth.js/classes/SynthSource/methods/rotate.md"},{"text":"scale","link":"/api/textmode.synth.js/classes/SynthSource/methods/scale.md"},{"text":"scroll","link":"/api/textmode.synth.js/classes/SynthSource/methods/scroll.md"},{"text":"scrollX","link":"/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md"},{"text":"scrollY","link":"/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md"},{"text":"pixelate","link":"/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md"},{"text":"repeat","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeat.md"},{"text":"repeatX","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md"},{"text":"repeatY","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md"},{"text":"kaleid","link":"/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md"},{"text":"polar","link":"/api/textmode.synth.js/classes/SynthSource/methods/polar.md"},{"text":"twirl","link":"/api/textmode.synth.js/classes/SynthSource/methods/twirl.md"},{"text":"swirl","link":"/api/textmode.synth.js/classes/SynthSource/methods/swirl.md"},{"text":"mirror","link":"/api/textmode.synth.js/classes/SynthSource/methods/mirror.md"},{"text":"shear","link":"/api/textmode.synth.js/classes/SynthSource/methods/shear.md"},{"text":"barrel","link":"/api/textmode.synth.js/classes/SynthSource/methods/barrel.md"},{"text":"pinch","link":"/api/textmode.synth.js/classes/SynthSource/methods/pinch.md"},{"text":"fisheye","link":"/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md"},{"text":"osc","link":"/api/textmode.synth.js/classes/SynthSource/methods/osc.md"},{"text":"noise","link":"/api/textmode.synth.js/classes/SynthSource/methods/noise.md"},{"text":"plasma","link":"/api/textmode.synth.js/classes/SynthSource/methods/plasma.md"},{"text":"moire","link":"/api/textmode.synth.js/classes/SynthSource/methods/moire.md"},{"text":"voronoi","link":"/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md"},{"text":"gradient","link":"/api/textmode.synth.js/classes/SynthSource/methods/gradient.md"},{"text":"shape","link":"/api/textmode.synth.js/classes/SynthSource/methods/shape.md"},{"text":"solid","link":"/api/textmode.synth.js/classes/SynthSource/methods/solid.md"},{"text":"src","link":"/api/textmode.synth.js/classes/SynthSource/methods/src.md"}]}]}]},{"text":"Interfaces","collapsed":true,"items":[{"text":"SynthContext","link":"/api/textmode.synth.js/interfaces/SynthContext.md"},{"text":"ModulatedArray","link":"/api/textmode.synth.js/interfaces/ModulatedArray.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"fast","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md"},{"text":"smooth","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md"},{"text":"ease","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md"},{"text":"offset","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md"},{"text":"fit","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md"}]}]}]},{"text":"Type Aliases","collapsed":true,"items":[{"text":"SynthParameterValue","link":"/api/textmode.synth.js/type-aliases/SynthParameterValue.md"},{"text":"EasingFunction","link":"/api/textmode.synth.js/type-aliases/EasingFunction.md"},{"text":"DynamicErrorCallback","link":"/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md"}]},{"text":"Variables","collapsed":true,"items":[{"text":"SynthPlugin","link":"/api/textmode.synth.js/variables/SynthPlugin.md"},{"text":"EASING_FUNCTIONS","link":"/api/textmode.synth.js/variables/EASING_FUNCTIONS.md"}]},{"text":"Functions","collapsed":true,"items":[{"text":"cellColor","link":"/api/textmode.synth.js/functions/cellColor.md"},{"text":"char","link":"/api/textmode.synth.js/functions/char.md"},{"text":"charColor","link":"/api/textmode.synth.js/functions/charColor.md"},{"text":"gradient","link":"/api/textmode.synth.js/functions/gradient.md"},{"text":"noise","link":"/api/textmode.synth.js/functions/noise.md"},{"text":"plasma","link":"/api/textmode.synth.js/functions/plasma.md"},{"text":"moire","link":"/api/textmode.synth.js/functions/moire.md"},{"text":"osc","link":"/api/textmode.synth.js/functions/osc.md"},{"text":"paint","link":"/api/textmode.synth.js/functions/paint.md"},{"text":"shape","link":"/api/textmode.synth.js/functions/shape.md"},{"text":"solid","link":"/api/textmode.synth.js/functions/solid.md"},{"text":"src","link":"/api/textmode.synth.js/functions/src.md"},{"text":"voronoi","link":"/api/textmode.synth.js/functions/voronoi.md"},{"text":"setGlobalErrorCallback","link":"/api/textmode.synth.js/functions/setGlobalErrorCallback.md"}]}] \ No newline at end of file +[{"text":"Live-Coding Errors","collapsed":true,"items":[{"text":"DynamicErrorCallback","link":"/api/textmode.synth.js/type-aliases/DynamicErrorCallback.md"},{"text":"setGlobalErrorCallback","link":"/api/textmode.synth.js/functions/setGlobalErrorCallback.md"}]},{"text":"Output Channels","collapsed":true,"items":[{"text":"cellColor","link":"/api/textmode.synth.js/functions/cellColor.md"},{"text":"char","link":"/api/textmode.synth.js/functions/char.md"},{"text":"charColor","link":"/api/textmode.synth.js/functions/charColor.md"},{"text":"paint","link":"/api/textmode.synth.js/functions/paint.md"}]},{"text":"Parameter Modulation","collapsed":true,"items":[{"text":"ModulatedArray","link":"/api/textmode.synth.js/interfaces/ModulatedArray.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"ease","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/ease.md"},{"text":"fast","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/fast.md"},{"text":"fit","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/fit.md"},{"text":"offset","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/offset.md"},{"text":"smooth","link":"/api/textmode.synth.js/interfaces/ModulatedArray/methods/smooth.md"}]}]},{"text":"SynthContext","link":"/api/textmode.synth.js/interfaces/SynthContext.md"},{"text":"EasingFunction","link":"/api/textmode.synth.js/type-aliases/EasingFunction.md"},{"text":"SynthParameterValue","link":"/api/textmode.synth.js/type-aliases/SynthParameterValue.md"},{"text":"EASING_FUNCTIONS","link":"/api/textmode.synth.js/variables/EASING_FUNCTIONS.md"}]},{"text":"Sources & Sampling","collapsed":true,"items":[{"text":"gradient","link":"/api/textmode.synth.js/functions/gradient.md"},{"text":"moire","link":"/api/textmode.synth.js/functions/moire.md"},{"text":"noise","link":"/api/textmode.synth.js/functions/noise.md"},{"text":"osc","link":"/api/textmode.synth.js/functions/osc.md"},{"text":"plasma","link":"/api/textmode.synth.js/functions/plasma.md"},{"text":"shape","link":"/api/textmode.synth.js/functions/shape.md"},{"text":"solid","link":"/api/textmode.synth.js/functions/solid.md"},{"text":"src","link":"/api/textmode.synth.js/functions/src.md"},{"text":"voronoi","link":"/api/textmode.synth.js/functions/voronoi.md"}]},{"text":"Synthesis Chains","collapsed":true,"items":[{"text":"SynthSource","link":"/api/textmode.synth.js/classes/SynthSource.md","collapsed":true,"items":[{"text":"Methods","collapsed":true,"items":[{"text":"add","link":"/api/textmode.synth.js/classes/SynthSource/methods/add.md"},{"text":"b","link":"/api/textmode.synth.js/classes/SynthSource/methods/b.md"},{"text":"barrel","link":"/api/textmode.synth.js/classes/SynthSource/methods/barrel.md"},{"text":"blend","link":"/api/textmode.synth.js/classes/SynthSource/methods/blend.md"},{"text":"brightness","link":"/api/textmode.synth.js/classes/SynthSource/methods/brightness.md"},{"text":"burn","link":"/api/textmode.synth.js/classes/SynthSource/methods/burn.md"},{"text":"cellColor","link":"/api/textmode.synth.js/classes/SynthSource/methods/cellColor.md"},{"text":"char","link":"/api/textmode.synth.js/classes/SynthSource/methods/char.md"},{"text":"charColor","link":"/api/textmode.synth.js/classes/SynthSource/methods/charColor.md"},{"text":"charMap","link":"/api/textmode.synth.js/classes/SynthSource/methods/charMap.md"},{"text":"clamp","link":"/api/textmode.synth.js/classes/SynthSource/methods/clamp.md"},{"text":"clone","link":"/api/textmode.synth.js/classes/SynthSource/methods/clone.md"},{"text":"color","link":"/api/textmode.synth.js/classes/SynthSource/methods/color.md"},{"text":"colorama","link":"/api/textmode.synth.js/classes/SynthSource/methods/colorama.md"},{"text":"contrast","link":"/api/textmode.synth.js/classes/SynthSource/methods/contrast.md"},{"text":"darken","link":"/api/textmode.synth.js/classes/SynthSource/methods/darken.md"},{"text":"diff","link":"/api/textmode.synth.js/classes/SynthSource/methods/diff.md"},{"text":"dodge","link":"/api/textmode.synth.js/classes/SynthSource/methods/dodge.md"},{"text":"fisheye","link":"/api/textmode.synth.js/classes/SynthSource/methods/fisheye.md"},{"text":"g","link":"/api/textmode.synth.js/classes/SynthSource/methods/g.md"},{"text":"gamma","link":"/api/textmode.synth.js/classes/SynthSource/methods/gamma.md"},{"text":"gradient","link":"/api/textmode.synth.js/classes/SynthSource/methods/gradient.md"},{"text":"hardlight","link":"/api/textmode.synth.js/classes/SynthSource/methods/hardlight.md"},{"text":"hue","link":"/api/textmode.synth.js/classes/SynthSource/methods/hue.md"},{"text":"invert","link":"/api/textmode.synth.js/classes/SynthSource/methods/invert.md"},{"text":"kaleid","link":"/api/textmode.synth.js/classes/SynthSource/methods/kaleid.md"},{"text":"layer","link":"/api/textmode.synth.js/classes/SynthSource/methods/layer.md"},{"text":"levels","link":"/api/textmode.synth.js/classes/SynthSource/methods/levels.md"},{"text":"lighten","link":"/api/textmode.synth.js/classes/SynthSource/methods/lighten.md"},{"text":"luma","link":"/api/textmode.synth.js/classes/SynthSource/methods/luma.md"},{"text":"mask","link":"/api/textmode.synth.js/classes/SynthSource/methods/mask.md"},{"text":"mirror","link":"/api/textmode.synth.js/classes/SynthSource/methods/mirror.md"},{"text":"modulate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulate.md"},{"text":"modulateHue","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateHue.md"},{"text":"modulateKaleid","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateKaleid.md"},{"text":"modulatePixelate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulatePixelate.md"},{"text":"modulateRepeat","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeat.md"},{"text":"modulateRepeatX","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatX.md"},{"text":"modulateRepeatY","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRepeatY.md"},{"text":"modulateRotate","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateRotate.md"},{"text":"modulateScale","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScale.md"},{"text":"modulateScrollX","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollX.md"},{"text":"modulateScrollY","link":"/api/textmode.synth.js/classes/SynthSource/methods/modulateScrollY.md"},{"text":"moire","link":"/api/textmode.synth.js/classes/SynthSource/methods/moire.md"},{"text":"mult","link":"/api/textmode.synth.js/classes/SynthSource/methods/mult.md"},{"text":"noise","link":"/api/textmode.synth.js/classes/SynthSource/methods/noise.md"},{"text":"osc","link":"/api/textmode.synth.js/classes/SynthSource/methods/osc.md"},{"text":"overlay","link":"/api/textmode.synth.js/classes/SynthSource/methods/overlay.md"},{"text":"paint","link":"/api/textmode.synth.js/classes/SynthSource/methods/paint.md"},{"text":"pinch","link":"/api/textmode.synth.js/classes/SynthSource/methods/pinch.md"},{"text":"pixelate","link":"/api/textmode.synth.js/classes/SynthSource/methods/pixelate.md"},{"text":"plasma","link":"/api/textmode.synth.js/classes/SynthSource/methods/plasma.md"},{"text":"polar","link":"/api/textmode.synth.js/classes/SynthSource/methods/polar.md"},{"text":"posterize","link":"/api/textmode.synth.js/classes/SynthSource/methods/posterize.md"},{"text":"r","link":"/api/textmode.synth.js/classes/SynthSource/methods/r.md"},{"text":"repeat","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeat.md"},{"text":"repeatX","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeatX.md"},{"text":"repeatY","link":"/api/textmode.synth.js/classes/SynthSource/methods/repeatY.md"},{"text":"rotate","link":"/api/textmode.synth.js/classes/SynthSource/methods/rotate.md"},{"text":"saturate","link":"/api/textmode.synth.js/classes/SynthSource/methods/saturate.md"},{"text":"scale","link":"/api/textmode.synth.js/classes/SynthSource/methods/scale.md"},{"text":"screen","link":"/api/textmode.synth.js/classes/SynthSource/methods/screen.md"},{"text":"scroll","link":"/api/textmode.synth.js/classes/SynthSource/methods/scroll.md"},{"text":"scrollX","link":"/api/textmode.synth.js/classes/SynthSource/methods/scrollX.md"},{"text":"scrollY","link":"/api/textmode.synth.js/classes/SynthSource/methods/scrollY.md"},{"text":"seed","link":"/api/textmode.synth.js/classes/SynthSource/methods/seed.md"},{"text":"shape","link":"/api/textmode.synth.js/classes/SynthSource/methods/shape.md"},{"text":"shear","link":"/api/textmode.synth.js/classes/SynthSource/methods/shear.md"},{"text":"shift","link":"/api/textmode.synth.js/classes/SynthSource/methods/shift.md"},{"text":"softlight","link":"/api/textmode.synth.js/classes/SynthSource/methods/softlight.md"},{"text":"solid","link":"/api/textmode.synth.js/classes/SynthSource/methods/solid.md"},{"text":"src","link":"/api/textmode.synth.js/classes/SynthSource/methods/src.md"},{"text":"sub","link":"/api/textmode.synth.js/classes/SynthSource/methods/sub.md"},{"text":"swirl","link":"/api/textmode.synth.js/classes/SynthSource/methods/swirl.md"},{"text":"thresh","link":"/api/textmode.synth.js/classes/SynthSource/methods/thresh.md"},{"text":"twirl","link":"/api/textmode.synth.js/classes/SynthSource/methods/twirl.md"},{"text":"voronoi","link":"/api/textmode.synth.js/classes/SynthSource/methods/voronoi.md"}]}]}]},{"text":"Workflow","collapsed":true,"items":[{"text":"SynthPlugin","link":"/api/textmode.synth.js/variables/SynthPlugin.md"}]}] \ No newline at end of file diff --git a/api/textmode.synth.js/variables/EASING_FUNCTIONS.md b/api/textmode.synth.js/variables/EASING_FUNCTIONS.md index d9aca2d4..54cca95a 100644 --- a/api/textmode.synth.js/variables/EASING_FUNCTIONS.md +++ b/api/textmode.synth.js/variables/EASING_FUNCTIONS.md @@ -7,7 +7,7 @@ category: Variables api: true kind: Variable ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / EASING\_FUNCTIONS @@ -24,18 +24,18 @@ Easing functions from https://gist.github.com/gre/1650294 | Name | Type | | ------ | ------ | -| `linear()` | (`t`) => `number` | -| `easeInQuad()` | (`t`) => `number` | -| `easeOutQuad()` | (`t`) => `number` | -| `easeInOutQuad()` | (`t`) => `number` | | `easeInCubic()` | (`t`) => `number` | -| `easeOutCubic()` | (`t`) => `number` | | `easeInOutCubic()` | (`t`) => `number` | -| `easeInQuart()` | (`t`) => `number` | -| `easeOutQuart()` | (`t`) => `number` | +| `easeInOutQuad()` | (`t`) => `number` | | `easeInOutQuart()` | (`t`) => `number` | +| `easeInOutQuint()` | (`t`) => `number` | +| `easeInQuad()` | (`t`) => `number` | +| `easeInQuart()` | (`t`) => `number` | | `easeInQuint()` | (`t`) => `number` | +| `easeOutCubic()` | (`t`) => `number` | +| `easeOutQuad()` | (`t`) => `number` | +| `easeOutQuart()` | (`t`) => `number` | | `easeOutQuint()` | (`t`) => `number` | -| `easeInOutQuint()` | (`t`) => `number` | +| `linear()` | (`t`) => `number` | | `sin()` | (`t`) => `number` | diff --git a/api/textmode.synth.js/variables/SynthPlugin.md b/api/textmode.synth.js/variables/SynthPlugin.md index a763f560..c79942b4 100644 --- a/api/textmode.synth.js/variables/SynthPlugin.md +++ b/api/textmode.synth.js/variables/SynthPlugin.md @@ -7,7 +7,7 @@ category: Variables api: true kind: Variable ecosystem: textmode.js -lastModified: 2026-07-31 +lastModified: 2026-08-01 --- [textmode.synth.js](../index.md) / SynthPlugin From a62bdec5d8a2dc79a9d8a8458fa366b806f3f4a6 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Mon, 3 Aug 2026 00:20:52 +0200 Subject: [PATCH 17/43] docs: update Node.js requirement to 24 LTS in installation guide --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index fcbef7a8..bb967fce 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -27,7 +27,7 @@ Use it to learn the ecosystem, prototype an idea, or decide which packages your - A modern browser with [`WebGL2`](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext) support -- [Node.js 20.8.1 or newer](https://nodejs.org/) and npm when using the package-manager workflow +- [Node.js 24 LTS](https://nodejs.org/) and npm when using the package-manager workflow You do not need to create a `` element yourself. Unless you provide one, `textmode.js` creates and mounts a canvas after the document body is available. From 7920bb98dc13f76816284ffb9a7ddf50c408f227 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Mon, 3 Aug 2026 00:34:15 +0200 Subject: [PATCH 18/43] docs: add FIGlet typography guide and reference in fonts documentation --- docs/figlet-typography.md | 230 ++++++++++++++++++++++++++++++++++++++ docs/fonts.md | 5 + docs/plugins.md | 5 +- 3 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 docs/figlet-typography.md diff --git a/docs/figlet-typography.md b/docs/figlet-typography.md new file mode 100644 index 00000000..fa42101d --- /dev/null +++ b/docs/figlet-typography.md @@ -0,0 +1,230 @@ +--- +title: FIGlet typography +description: Load FIGfonts, layout ASCII banner text, align baselines, and style per-cell characters with textmode.figlet.js. +--- + +# FIGlet typography + +FIGlet display typography gives `textmode.js` sketches large, stylized ASCII text banners, headers, and retro titles. + +The separate [`textmode.figlet.js`](/api/textmode.figlet.js/) package adds FIGfont parsing, standards-aware layout (fitting, smushing, wrapping), baseline alignment, and per-cell character and cell coloring. (✿◠‿◠) + +## Install and register the plugin + +Pass [`FigletPlugin`](/api/textmode.figlet.js/variables/FigletPlugin.md) to `textmode.create()` via the `plugins` option: + +```js +import { textmode } from "textmode.js"; +import { FigletPlugin } from "textmode.figlet.js"; + +const t = textmode.create({ + width: 800, + height: 600, + plugins: [FigletPlugin], +}); +``` + +Installing `FigletPlugin` registers FIGlet extension methods on your [`Textmodifier`](/api/textmode.js/classes/Textmodifier.md) instance, documented in [`TextmodifierFigletExtensions`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md). + +## Load and select FIGfonts + +Before rendering FIGlet text, load a `.flf` font file and set it as active. + +### Load a font from URL or path + +Use [`t.loadFigFont()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/loadFigFont.md) to load a `.flf` font file asynchronously: + +```js +t.setup(async () => { + const font = await t.loadFigFont("./fonts/standard.flf"); + t.figFont(font); +}); +``` + +### Parse raw FIGfont data + +Use [`t.parseFigFont()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/parseFigFont.md) when working with preloaded string data: + +```js +const font = t.parseFigFont("standard", rawFlfString); +t.figFont(font); +``` + +### Manage the active font + +Use [`t.figFont()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figFont.md) to retrieve or update the active FIGfont: + +```js +// Set active font +t.figFont(font); + +// Get current active font +const activeFont = t.figFont(); +``` + +Calling `t.figText()` without an active font throws an error. + +## Render FIGlet text + +Use [`t.figText()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figText.md) inside your `draw()` loop to render text at grid column and row coordinates: + +```js +t.draw(() => { + t.background(0); + t.charColor(255, 255, 255); + + t.figText("TEXTMODE", 5, 10); +}); +``` + +`figText()` translates and positions each sub-character cell into the active textmode layer, using the layer's current state for missing per-cell color overrides. + +## Alignment and baselines + +Positioning FIGlet text depends on horizontal alignment and vertical baselines. + +### Horizontal alignment + +Use [`t.figTextAlign()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextAlign.md) or specify `alignment` to shift the text origin: + +```js +t.figTextAlign("center"); // 'left' | 'center' | 'right' +t.figText("HERO", t.grid.cols / 2, 5); +``` + +- `'left'` (default): origin is at the leftmost column. +- `'center'`: origin is horizontally centered across all rendered columns. +- `'right'`: origin is at the rightmost column. + +### Vertical baseline + +Use [`t.figTextBaseline()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBaseline.md) to adjust vertical positioning: + +```js +t.figTextBaseline("center"); // 'top' | 'center' | 'bottom' | 'baseline' +t.figText("TITLE", t.grid.cols / 2, t.grid.rows / 2); +``` + +- `'baseline'` (default): anchors to the font's declared baseline row. +- `'top'`: anchors to row `0` (top line of characters). +- `'center'`: anchors to the vertical midpoint of all rendered rows. +- `'bottom'`: anchors to the bottommost row of the rendered block. + +## Layout options and wrapping + +Pass a [`FigTextOptions`](/api/textmode.figlet.js/interfaces/FigTextOptions.md) object to `t.figText()` to control layout algorithms, line wrapping, and direction: + +```js +t.figText("COMPACT HEADER", 0, 0, { + horizontalLayout: "smushed", + verticalLayout: "fitted", + wrap: "word", + maxCols: 40, +}); +``` + +### Layout modes + +FIGlet supports three layout density modes for both axes: + +- `'full'`: Full character width/height with no overlapping or kerning. +- `'fitted'`: Characters are moved together until they touch without overlapping. +- `'smushed'`: Characters overlap according to FIGlet smushing rules (e.g. hierarchy, hardblanks, border merging). + +### Multiline wrapping + +Use `wrap` and `maxCols` to automatically break long text onto multiple logical lines: + +- `wrap: 'none'` (default): Text stays on a single line (unless explicit `\n` characters are present). +- `wrap: 'word'`: Wraps at whitespace boundaries when total width exceeds `maxCols`. +- `wrap: 'char'`: Wraps character-by-character when total width exceeds `maxCols`. + +### Print direction + +Set `direction` to override font-defined layout direction: + +- `'font'` (default): Respects the direction specified in the font header. +- `'ltr'`: Render left-to-right. +- `'rtl'`: Render right-to-left. + +## Per-cell styling and color resolvers + +Apply custom colors to rendered FIGlet characters using `charColor` (foreground) and `cellColor` (background) in `FigTextOptions`. + +### Static colors + +Pass any valid textmode color value (hex, rgb array, string, number): + +```js +t.figText("GLOW", 2, 4, { + charColor: [255, 200, 50], + cellColor: "#110022", +}); +``` + +### Dynamic color callbacks + +For gradients, rainbow effects, or per-character highlights, pass a resolver function that accepts [`FigTextCellContext`](/api/textmode.figlet.js/interfaces/FigTextCellContext.md): + +```js +t.figText("RAINBOW", 0, 5, { + charColor: (cell) => { + const hue = (cell.col * 15 + t.frameCount * 2) % 360; + return t.color.hsl(hue, 80, 60); + }, +}); +``` + +The `cell` context object provides details for precise styling: + +- `cell.char`: The sub-character symbol for this cell. +- `cell.col`: Absolute column index within the rendered FIGlet result. +- `cell.row`: Absolute row index within the rendered FIGlet result. +- `cell.inputIndex`: Index of the character in the input string. +- `cell.inputChar`: The original input character (e.g. `'R'`). +- `cell.figCharCode`: Unicode code point of the character. +- `cell.subRow`: Row within the source FIGcharacter. +- `cell.subCol`: Column within the source FIGcharacter. +- `cell.lineIndex`: Logical line index after wrapping or line breaks. + +## Measurement and bounds + +Calculate the dimensions of FIGlet text before drawing to center elements, build bounding boxes, or dynamically size layouts with [`t.figTextWidth()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextWidth.md), [`t.figTextHeight()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextHeight.md), and [`t.figTextBounds()`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions/methods/figTextBounds.md): + +```js +const width = t.figTextWidth("HEADER", { horizontalLayout: "fitted" }); +const height = t.figTextHeight("HEADER"); +const bounds = t.figTextBounds("HEADER"); // { cols: number, rows: number } +``` + +### Inspecting parsed `TextmodeFigFont` + +Inspect font metadata and low-level character plans directly on a [`TextmodeFigFont`](/api/textmode.figlet.js/classes/TextmodeFigFont.md) instance: + +```js +const font = t.figFont(); + +console.log(font.name); // Font name +console.log(font.height); // FIGcharacter height in rows +console.log(font.baseline); // Declared font baseline row +console.log(font.hardblank); // Hardblank character +console.log(font.defaultLayout); // Default horizontal layout + +// Inspect individual FIGcharacter +const charData = font.getCharacter("A"); + +// Generate low-level plan without drawing +const plan = font.planText("HELLO"); +// plan.cells, plan.lines, plan.cols, plan.rows +``` + +## Related APIs + +- [`textmode.figlet.js` API reference](/api/textmode.figlet.js/) +- [`FigletPlugin`](/api/textmode.figlet.js/variables/FigletPlugin.md) +- [`TextmodifierFigletExtensions`](/api/textmode.figlet.js/interfaces/TextmodifierFigletExtensions.md) +- [`TextmodeFigFont`](/api/textmode.figlet.js/classes/TextmodeFigFont.md) +- [`FigTextOptions`](/api/textmode.figlet.js/interfaces/FigTextOptions.md) +- [`FigTextCellContext`](/api/textmode.figlet.js/interfaces/FigTextCellContext.md) +- [Fonts and tilesets](/docs/fonts) +- [Plugins](/docs/plugins) diff --git a/docs/fonts.md b/docs/fonts.md index 71e2233f..78de738b 100644 --- a/docs/fonts.md +++ b/docs/fonts.md @@ -292,6 +292,10 @@ Use a bitmap tileset when you want: - icon-like or sprite-like cells - preserved authored colors via `useTileColors()` +## FIGlet display typography + +For bold display headers, titles, and FIGfont banners rendered across multiple cells, use the official [`textmode.figlet.js`](/api/textmode.figlet.js/) add-on. See the [FIGlet typography guide](/docs/figlet-typography) for font loading, layout density, alignment, and per-cell styling options. + ## Discover more fonts The curated font list lives in [`awesome-textmode`](https://github.com/humanbydefinition/awesome-textmode): @@ -314,3 +318,4 @@ The curated font list lives in [`awesome-textmode`](https://github.com/humanbyde - [`TextmodeFont`](/api/textmode.js/namespaces/fonts/classes/TextmodeFont.md) - [`TextmodeTileset`](/api/textmode.js/namespaces/fonts/classes/TextmodeTileset.md) - [`TextmodeTilesetOptions`](/api/textmode.js/namespaces/fonts/interfaces/TextmodeTilesetOptions.md) +- [FIGlet typography](/docs/figlet-typography) diff --git a/docs/plugins.md b/docs/plugins.md index bc1459f7..2624f91c 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -15,12 +15,13 @@ Pass plugins through [`TextmodeOptions.plugins`](/api/textmode.js/type-aliases/T ```js import { textmode } from "textmode.js"; -import { SynthPlugin } from "textmode.synth.js"; +import { FigletPlugin } from "textmode.figlet.js"; +import { FiltersPlugin } from "textmode.filters.js"; const t = textmode.create({ width: 800, height: 600, - plugins: [SynthPlugin], + plugins: [FigletPlugin, FiltersPlugin], }); ``` From ab41ac7915f954ba51d464a14c91f16a43331eea Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Mon, 3 Aug 2026 00:35:59 +0200 Subject: [PATCH 19/43] docs: update section title and improve font discovery instructions --- docs/fonts.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/fonts.md b/docs/fonts.md index 78de738b..deb4a509 100644 --- a/docs/fonts.md +++ b/docs/fonts.md @@ -296,11 +296,10 @@ Use a bitmap tileset when you want: For bold display headers, titles, and FIGfont banners rendered across multiple cells, use the official [`textmode.figlet.js`](/api/textmode.figlet.js/) add-on. See the [FIGlet typography guide](/docs/figlet-typography) for font loading, layout density, alignment, and per-cell styling options. -## Discover more fonts +## Discover fonts The curated font list lives in [`awesome-textmode`](https://github.com/humanbydefinition/awesome-textmode): -- [`humanbydefinition/awesome-textmode`](https://github.com/humanbydefinition/awesome-textmode) - [Fonts](https://github.com/humanbydefinition/awesome-textmode#fonts) - [Font collections](https://github.com/humanbydefinition/awesome-textmode#font-collections) From 9c5bca5dd253b3859f69e5306da2fb3c250cccf7 Mon Sep 17 00:00:00 2001 From: humanbydefinition Date: Mon, 3 Aug 2026 00:57:57 +0200 Subject: [PATCH 20/43] refactor: update FeaturedSketches component to use community sketches from editor.textmode.art --- .vitepress/data/editorSketches.data.ts | 99 +++ .vitepress/data/sketches.json | 57 -- .../ExampleSketchBrowser.vue | 751 ++++-------------- .../FeaturedSketches/FeaturedSketches.vue | 88 +- .../theme/components/TextmodeSandbox.vue | 101 ++- scripts/fetch-editor-sketches.mjs | 89 +++ 6 files changed, 474 insertions(+), 711 deletions(-) create mode 100644 .vitepress/data/editorSketches.data.ts delete mode 100644 .vitepress/data/sketches.json create mode 100644 scripts/fetch-editor-sketches.mjs diff --git a/.vitepress/data/editorSketches.data.ts b/.vitepress/data/editorSketches.data.ts new file mode 100644 index 00000000..0be818a1 --- /dev/null +++ b/.vitepress/data/editorSketches.data.ts @@ -0,0 +1,99 @@ +export interface EditorSketchMeta { + slug: string + title: string + description?: string + authorName?: string + license?: string + socialLinks?: Array<{ label: string; url: string }> + createdAt?: string + ogFrame?: number + ogDarken?: number + featured?: boolean +} + +export interface EditorGallerySketch extends EditorSketchMeta { + textmodeCode: string + ogImageUrl?: string +} + +export type EditorSketchMap = Record + +declare const data: EditorGallerySketch[] +export { data } + +/** + * Ensures sketch code is standalone executable by prepending `const t = textmode.create();` + * if `t` is not already initialized. + */ +export function refactorSketchCode(code: string): string { + const trimmed = code.trim() + if ( + trimmed.includes('const t = textmode.create') || + trimmed.includes('let t = textmode.create') || + trimmed.includes('var t = textmode.create') + ) { + return code + } + return `const t = textmode.create();\n\n${code}` +} + +const GITHUB_REPO_OWNER = 'humanbydefinition' +const GITHUB_REPO_NAME = 'editor.textmode.art' +const GITHUB_BRANCH = 'main' + +async function fetchFromGitHub(): Promise { + try { + const apiUrl = `https://api.github.com/repos/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/contents/sketches` + const headers: Record = { + 'User-Agent': 'code.textmode.art-build-loader', + Accept: 'application/vnd.github.v3+json', + } + if (process.env.GITHUB_TOKEN) { + headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}` + } + + const res = await fetch(apiUrl, { headers }) + if (!res.ok) { + console.warn(`[editorSketches loader] GitHub API failed (${res.status} ${res.statusText}). Returning empty sketches.`) + return [] + } + + const items = (await res.json()) as Array<{ name: string; type: string }> + const sketchFolders = items.filter((item) => item.type === 'dir').map((item) => item.name) + + const sketches: EditorGallerySketch[] = [] + + for (const slug of sketchFolders) { + const rawBase = `https://raw.githubusercontent.com/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}/${GITHUB_BRANCH}/sketches/${slug}` + const metaRes = await fetch(`${rawBase}/meta.json`, { headers }) + const codeRes = await fetch(`${rawBase}/sketch.js`, { headers }) + + if (!metaRes.ok || !codeRes.ok) continue + + const meta = (await metaRes.json()) as EditorSketchMeta + const rawCode = await codeRes.text() + const textmodeCode = refactorSketchCode(rawCode) + const ogImageUrl = `${rawBase}/og.png` + + sketches.push({ + ...meta, + slug: meta.slug || slug, + featured: true, + textmodeCode, + ogImageUrl, + }) + } + + return sketches.sort((a, b) => a.slug.localeCompare(b.slug)) + } catch (error) { + console.warn('[editorSketches loader] Exception fetching from GitHub:', error) + return [] + } +} + +export default { + async load(): Promise { + // Strictly fetch published sketches from the remote main branch on GitHub + return await fetchFromGitHub() + }, +} diff --git a/.vitepress/data/sketches.json b/.vitepress/data/sketches.json deleted file mode 100644 index b4b0a644..00000000 --- a/.vitepress/data/sketches.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "wave-interference": { - "title": "Animated wave pattern", - "author": "humanbydefinition", - "featured": true - }, - "digital-rain": { - "title": "Digital rain", - "author": "humanbydefinition", - "featured": true - }, - "plasma-field": { - "title": "Plasma field", - "author": "humanbydefinition", - "featured": true - }, - "webcam": { - "title": "Webcam Integration", - "author": "humanbydefinition", - "featured": false - }, - "video": { - "title": "Video Processing", - "author": "humanbydefinition", - "featured": false - }, - "threejs": { - "title": "Three.js Integration", - "author": "humanbydefinition", - "featured": false - }, - "shader-noise": { - "title": "Shader Noise", - "author": "humanbydefinition", - "featured": false - }, - "primitives": { - "title": "Primitives Showcase", - "author": "humanbydefinition", - "featured": false - }, - "p5js": { - "title": "p5.js Integration", - "author": "humanbydefinition", - "featured": false - }, - "hydra-synth": { - "title": "Hydra Synth Integration", - "author": "humanbydefinition", - "featured": false - }, - "entity-wave-prop": { - "title": "Entity Based Wave Propagation", - "author": "trintlermint", - "featured": true - } -} diff --git a/.vitepress/theme/components/ExampleSketchBrowser/ExampleSketchBrowser.vue b/.vitepress/theme/components/ExampleSketchBrowser/ExampleSketchBrowser.vue index efc55ae4..500c8c06 100644 --- a/.vitepress/theme/components/ExampleSketchBrowser/ExampleSketchBrowser.vue +++ b/.vitepress/theme/components/ExampleSketchBrowser/ExampleSketchBrowser.vue @@ -13,7 +13,7 @@

- {{ currentPosition }} / {{ sketchIds.length }} + {{ currentPosition }} / {{ sketches.length }}