2026-05-29 17:17:06 -04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
qft - carpet . mjs — render VACUUM CARPET studies + a plexi deck .
Logic lives in src / qft / carpet . js ( shared with tools / layering . mjs ) .
Usage : node tools / qft - carpet . mjs [ size ]
=== === === === === === === === === === === === === === === === === === === === * /
import { writeFileSync , mkdirSync } from 'node:fs' ;
import { carpetSVG } from '../src/qft/carpet.js' ;
const SIZE = + ( process . argv [ 2 ] || 1500 ) ;
const ROOT = 'output/qft/carpet' ;
mkdirSync ( ` ${ ROOT } /explore ` , { recursive : true } ) ;
mkdirSync ( ` ${ ROOT } /layers ` , { recursive : true } ) ;
// EXPLORE — soft sinusoidal/spiralling blips across the chaos range
const EXPLORE = [
{ name : '01_calm-ridgeline' , label : 'calm · low-q swells, few blips' , o : { chaos : 0.22 , blips : 0.5 , rows : 44 , overlap : 1.6 } } ,
{ name : '02_vacuum-seethe' , label : 'vacuum seethe · many spiralling blips' , o : { chaos : 0.8 , blips : 1.4 , rows : 50 , overlap : 1.8 , salt : 'seethe' } } ,
{ name : '03_dense-fine' , label : 'dense fine weave' , o : { chaos : 0.5 , blips : 1.0 , rows : 70 , overlap : 1.5 , strokeNear : 1.2 , salt : 'fine' } } ,
{ name : '04_sparse-bold' , label : 'sparse · bold soft swells' , o : { chaos : 0.55 , blips : 0.9 , rows : 30 , overlap : 2.2 , strokeNear : 2.2 , salt : 'bold' } } ,
{ name : '05_deep-horizon' , label : 'deep horizon · more sky above the mound' , o : { chaos : 0.5 , blips : 0.9 , rows : 56 , horizon : 0.44 , wFar : 0.58 , wNear : 0.74 , salt : 'deep' } } ,
{ name : '06_verdigris-seethe' , label : 'verdigris vacuum · oxidised' , o : { chaos : 0.7 , blips : 1.2 , rows : 48 , hue : 0.40 , hue2 : 0.47 , sat : 0.42 , salt : 'verd' } } ,
] ;
console . log ( ` carpet · explore ( ${ EXPLORE . length } ) → ${ ROOT } /explore/ ` ) ;
for ( const v of EXPLORE ) {
writeFileSync ( ` ${ ROOT } /explore/ ${ v . name } .svg ` , carpetSVG ( SIZE , { ... v . o , mode : 'solid' } ) ) ;
console . log ( ` ${ v . name } — ${ v . label } ` ) ;
}
{
const cap = ( v ) => ` ${ v . name . replace ( /^\d+_/ , '' ) . replace ( /-/g , ' ' ) } · ${ v . label } ` ;
writeFileSync ( ` ${ ROOT } /explore/m.html ` , ` <!DOCTYPE html><html><head><meta charset="utf-8">
< style > html , body { margin : 0 ; background : # 222 } . grid { display : grid ; grid - template - columns : repeat ( 2 , 1 fr ) ; gap : 8 px ; padding : 10 px ; width : 2000 px } figure { margin : 0 ; position : relative ; background : # fff ; overflow : hidden } img { width : 100 % ; display : block } figcaption { position : absolute ; left : 0 ; bottom : 0 ; right : 0 ; padding : 6 px 10 px ; font : 13 px ui - monospace , monospace ; color : # fff ; background : linear - gradient ( transparent , # 000 d ) } < / s t y l e > < / h e a d > < b o d y >
< div class = "grid" > $ { EXPLORE . map ( v => ` <figure><img src=" ${ v . name } .svg"><figcaption> ${ cap ( v ) } </figcaption></figure> ` ) . join ( '' ) } < / d i v > < / b o d y > < / h t m l > ` ) ;
}
// LAYERS — three transparent PLATE sheets for a spaced plexi deck
const DECK = [
{ name : 'L3_back' , salt : 'fieldA' , hue : 0.58 , hue2 : 0.62 , chaos : 0.55 , blips : 0.8 } ,
{ name : 'L2_mid' , salt : 'fieldB' , hue : 0.52 , hue2 : 0.56 , chaos : 0.65 , blips : 1.0 } ,
{ name : 'L1_front' , salt : 'fieldC' , hue : 0.47 , hue2 : 0.50 , chaos : 0.75 , blips : 1.2 } ,
] ;
const deckBase = { mode : 'plate' , rows : 46 , horizon : 0.36 , wFar : 0.58 , wNear : 0.7 , overlap : 1.7 , mound : 0.4 , sat : 0.6 , lightNear : 0.33 , lightFar : 0.55 } ;
console . log ( ` carpet · plexi deck ( ${ DECK . length } ) → ${ ROOT } /layers/ ` ) ;
for ( const v of DECK ) { writeFileSync ( ` ${ ROOT } /layers/ ${ v . name } .svg ` , carpetSVG ( SIZE , { ... deckBase , ... v } ) ) ; console . log ( ` ${ v . name } ` ) ; }
2026-05-30 06:42:16 -04:00
// VERTICAL field studies — lines run vertically, receding to a side edge
mkdirSync ( ` ${ ROOT } /vertical ` , { recursive : true } ) ;
const VERT = [
{ name : '01_calm-curtain' , label : 'calm vertical curtain' , o : { orient : 'vertical' , chaos : 0.28 , blips : 0.6 , rows : 46 , overlap : 1.6 , mode : 'solid' } } ,
{ name : '02_seething-strings' , label : 'seething vertical strings' , o : { orient : 'vertical' , chaos : 0.75 , blips : 1.3 , rows : 52 , overlap : 1.8 , mode : 'solid' , salt : 'vstr' } } ,
{ name : '03_rays-plate' , label : 'fine vertical rays (plate)' , o : { orient : 'vertical' , chaos : 0.5 , blips : 0.9 , rows : 60 , overlap : 1.5 , mode : 'plate' , hue : 0.5 , hue2 : 0.55 , salt : 'vray' } } ,
] ;
console . log ( ` carpet · vertical ( ${ VERT . length } ) → ${ ROOT } /vertical/ ` ) ;
for ( const v of VERT ) { writeFileSync ( ` ${ ROOT } /vertical/ ${ v . name } .svg ` , carpetSVG ( SIZE , v . o ) ) ; console . log ( ` ${ v . name } — ${ v . label } ` ) ; }
writeFileSync ( ` ${ ROOT } /vertical/m.html ` , ` <!DOCTYPE html><html><head><meta charset="utf-8">
< style > html , body { margin : 0 ; background : # 222 } . grid { display : grid ; grid - template - columns : repeat ( 3 , 1 fr ) ; gap : 8 px ; padding : 10 px ; width : 2100 px } figure { margin : 0 ; position : relative ; background : # fff ; overflow : hidden } img { width : 100 % ; display : block } figcaption { position : absolute ; left : 0 ; bottom : 0 ; right : 0 ; padding : 6 px 10 px ; font : 13 px ui - monospace , monospace ; color : # fff ; background : linear - gradient ( transparent , # 000 d ) } < / s t y l e > < / h e a d > < b o d y >
< div class = "grid" > $ { VERT . map ( v => ` <figure><img src=" ${ v . name } .svg"><figcaption> ${ v . label } </figcaption></figure> ` ) . join ( '' ) } < / d i v > < / b o d y > < / h t m l > ` ) ;
2026-05-29 17:17:06 -04:00
writeFileSync ( ` ${ ROOT } /stack.html ` , ` <!DOCTYPE html><html><head><meta charset="utf-8"><title>vacuum carpet · plexi deck</title>
< style > html , body { margin : 0 ; background : # 0 c0c0c } . stage { position : relative ; width : $ { SIZE } px ; height : $ { SIZE } px ; margin : 30 px auto ; background : rgb ( 226 , 219 , 199 ) ; box - shadow : 0 0 120 px # 000 inset } . stage img { position : absolute ; inset : 0 ; width : 100 % ; height : 100 % } . L3 { filter : blur ( 2.2 px ) ; opacity : . 5 ; transform : translateY ( - 6 px ) scale ( 1.01 ) } . L2 { filter : blur ( 1 px ) ; opacity : . 72 ; transform : translateY ( - 2 px ) } . L1 { opacity : . 95 } . cap { max - width : $ { SIZE } px ; margin : 0 auto ; color : # 888 ; font : 12 px ui - monospace , monospace ; padding : 0 4 px } < / s t y l e > < / h e a d > < b o d y >
< div class = "stage" > < img class = "L3" src = "layers/L3_back.svg" > < img class = "L2" src = "layers/L2_mid.svg" > < img class = "L1" src = "layers/L1_front.svg" > < / d i v >
< p class = "cap" > deck ( back → front ) : film / diffusion · L3 · L2 · L1 · [ bubble chamber ] . back sheets blurred + dimmed = air - gap depth of field . < / p > < / b o d y > < / h t m l > ` ) ;
console . log ( ` stack -> ${ ROOT } /stack.html ; explore -> ${ ROOT } /explore/m.html ` ) ;