← Back to Blog
Media Art Article · 2026.11.05

AI와 만드는 트뤼셰 타일 제너러티브 패턴

AI에게 연결 규칙을 전달하고 p5.js의 두 가지 곡선 타일로 제너러티브 패턴을 만든다. 실제 실행한 코드와 화면을 바탕으로 난수 시드, 선택 확률, 타일 크기가 작품의 형태를 바꾸는 과정을 살핀다.

media-artgenerative-artcreative-codingp5jsAI

두 방향의 곡선 타일이 연결되는 모습을 표현한 개념 표지

위 표지는 생성형 AI로 만든 개념 이미지다. 아래에 실은 예제 실행 화면과는 구별된다.

작은 곡선 두 개가 들어 있는 정사각형을 반복해 화면을 채운다고 하자. 각 칸에서 곡선의 방향만 바꿔도 작은 고리와 길게 돌아가는 선이 섞인 패턴이 나타난다. 이번에는 이 방식의 트뤼셰 타일 패턴을 만든다. 목표는 무작위로 고른 타일들이 이웃한 칸과 끊김 없이 만나는 정지 화면이다.

AI에게 맡길 부분은 연결 규칙을 코드로 옮기고, 바꿔 볼 조건을 제안하는 일이다. 실제 화면은 p5.js가 정해진 규칙과 난수에 따라 그린다. 매번 이미지를 생성하는 모델을 호출하는 구조가 아니다. 생성형 AI의 제작 보조와 알고리즘 기반 제너러티브 아트를 이렇게 나누면, 어느 단계에서 결과를 고치고 다시 만들 수 있는지가 분명해진다.

이 예제에서는 960×540 화면, 두 가지 타일 방향, 한 가지 선 색을 사용한다. 변수는 몇 개뿐이지만 선택할 수 있는 화면은 많다. 코드를 늘리기 전에 타일 크기와 선택 확률만으로 어떤 차이가 생기는지 비교해 보자.

곡선의 끝을 같은 위치에 놓는다

정사각형 한 칸의 네 변에서 가운데 지점을 하나씩 잡는다. 첫 번째 타일은 위쪽 중점과 왼쪽 중점을 사분원으로 잇고, 아래쪽 중점과 오른쪽 중점을 다른 사분원으로 잇는다. 두 번째 타일은 위쪽과 오른쪽, 아래쪽과 왼쪽을 각각 잇는다. 어느 타일을 골라도 선이 칸 밖으로 나가는 위치는 네 변의 중점으로 같다.

이 규칙 때문에 옆 칸의 방향을 미리 알 필요가 없다. 오른쪽으로 나가는 끝은 이웃 칸의 왼쪽 끝과 만나고, 아래쪽으로 나가는 끝은 다음 줄의 위쪽 끝과 만난다. 칸 안에서 어느 쪽으로 돌아갈지만 달라진다. 화면 안의 연결은 유지되지만, 화면 가장자리에서 끝난 선을 반대편 가장자리로 잇는 규칙은 넣지 않는다. 이 예제를 그대로 벽지처럼 반복해도 바깥 테두리까지 이어진다고 가정해서는 안 된다.

코드에서 사용하는 p5.js의 arc()는 중심 위치, 타원의 너비와 높이, 시작 각도와 끝 각도를 받는다. 여기서는 원의 지름을 타일 한 변과 같게 둔다. 반지름이 타일의 절반이므로 모서리 중심의 사분원이 두 변의 중점에 닿는다. 지름과 반지름을 혼동해 두 배 크기의 호를 그리면 연결 위치부터 달라진다.

그림이 복잡해 보이는 이유는 타일 하나의 복잡성에 있지 않다. 두 종류의 연결이 반복되면서 긴 경로와 닫힌 고리가 생기기 때문이다. AI가 곡선을 더하거나 모양을 장식하더라도 이 네 개의 접점을 지키는지 먼저 살펴야 한다. 연결 규칙이 깨진 화면도 작품이 될 수 있지만, 그것이 의도한 단절인지 코드 오류인지는 구분해야 한다.

AI에게 화면과 연결 조건을 함께 요청한다

p5.js 공식 다운로드 페이지에서 안내하는 2.3.3을 기준으로 예제를 실행했다. 같은 버전의 p5.js 웹 에디터를 열고 sketch.js의 내용을 아래 코드로 바꾼 뒤 실행 버튼을 누른다. 별도의 이미지 파일이나 API 키는 필요하지 않다.

직접 코드를 변형하고 싶다면 먼저 AI에게 다음과 같은 제작 조건을 전달할 수 있다. 이는 특정 모델에서 같은 문장의 답변을 재현했다는 기록이 아니라, 코드 작성을 부탁할 때 사용할 요청 예시다.

p5.js 2.3.3에서 실행할 정지 패턴을 만들어 줘.
캔버스는 960×540, 정사각형 타일 한 변은 30이다.
각 타일에는 반지름 15인 사분원 두 개만 그려 줘.
네 변의 중점에서 이웃 타일의 선과 만나야 한다.
타일 방향은 두 가지이며 첫 방향의 선택 확률을 bias로 둬.
seed를 고정하면 같은 배치가 다시 나와야 한다.
색상, 선 굵기, cell, bias, seed를 바꿀 위치를 알려 줘.
이미지 생성 API, 애니메이션, 외부 이미지는 추가하지 마.

요청에서 결과물의 크기와 연결 위치를 숫자로 지정한 이유는 확인할 수 있는 답을 받기 위해서다. "유기적이고 멋진 패턴"이라는 말만으로는 선이 끊긴 이유를 판단하기 어렵다. 곡선이 만날 좌표를 먼저 정하면 AI의 코드가 조건을 지켰는지 직접 비교할 수 있다.

AI에게 색과 밀도에 대한 제안을 받더라도 한 번에 한 조건만 적용한다. 화면을 바꾸는 과정에서 난수 배치까지 계속 달라지면 무엇이 좋아졌는지 구분하기 어렵다. 공식 randomSeed() 문서가 설명하듯 일정한 시드로 난수열을 다시 만들 수 있다. 시드를 고정하고 선 굵기부터 비교하면 배치의 차이에 가려지지 않은 굵기의 효과를 볼 수 있다.

짧은 코드로 연결된 패턴을 그린다

const cfg = { seed: 17, cell: 30, bias: 0.5, weight: 0.16 };

function setup() {
	pixelDensity(1);
	createCanvas(960, 540);
	noLoop();
	drawPattern();
}

function drawPattern() {
	background('#102d35');
	noFill();
	stroke('#f3dfb1');
	strokeWeight(cfg.cell * cfg.weight);
	strokeCap(ROUND);
	angleMode(RADIANS);
	randomSeed(cfg.seed);
	const s = cfg.cell;
	for (let y = 0; y < height; y += s) {
		for (let x = 0; x < width; x += s) {
			if (random() < cfg.bias) {
				arc(x, y, s, s, 0, HALF_PI);
				arc(x + s, y + s, s, s, PI, PI + HALF_PI);
			} else {
				arc(x + s, y, s, s, HALF_PI, PI);
				arc(x, y + s, s, s, PI + HALF_PI, TWO_PI);
			}
		}
	}
}

p5.js 예제를 실제 실행한 960×540 트뤼셰 타일 패턴

실행하면 짙은 청록색 바탕에 연한 모래색 곡선이 나타난다. 30픽셀 타일이 가로 32칸, 세로 18칸을 채운다. 총 576개의 타일마다 사분원 두 개를 그리므로 호는 1,152개다. 위 화면은 이 코드의 기본 설정을 실제로 실행해 얻었다. 생성형 이미지 모델이 만든 예제 화면으로 대체하지 않았다.

drawPattern()은 그림을 그릴 때마다 randomSeed(cfg.seed)를 호출한다. 그다음 모든 칸을 같은 순서로 돌며 난수를 한 번씩 사용한다. 공식 random() 문서에 따르면 인수 없는 호출은 0 이상 1 미만의 수를 반환한다. 따라서 bias가 0이면 두 번째 방향만, 1이면 첫 번째 방향만 선택한다. 0.5에서는 두 방향을 같은 확률로 뽑지만, 한 화면의 실제 개수가 반드시 반반이라는 뜻은 아니다.

예제를 검증할 때는 같은 설정으로 다시 그린 화면이 같은지, 시드를 18로 바꾸면 배치가 달라지는지, 17로 되돌리면 원래 배치가 돌아오는지를 확인했다. 또한 선택 확률 0과 1에서 각각 한 방향만 나오는지 확인했다. 실제 그리기 호출의 호 끝점도 대조해 내부 경계에서는 두 끝점이, 바깥 테두리에서는 한 끝점이 만나는 것을 확인했다. 확인 범위는 p5.js 2.3.3과 이번 데스크톱 브라우저 실행이다. 다른 브라우저의 가장자리 픽셀까지 완전히 같다는 보장은 하지 않는다.

화면이 보이지 않으면 먼저 에디터가 사용하는 p5.js 버전과 오류 메시지를 확인한다. 그다음 AI에게 오류 문장과 해당 줄을 전달한다. 전체를 새로 작성하게 하기보다 현재 코드의 어떤 호출이 실패했는지 설명하고 그 부분을 수정하도록 요청하면, 이미 확인한 연결 규칙을 보존하기 쉽다.

확률과 크기로 관람 거리를 조절한다

첫 실험은 bias를 0, 0.5, 1로 바꾸는 것이다. 가운데 값에서는 방향이 섞이면서 고리와 긴 선이 함께 나타난다. 양 끝에서는 같은 방향의 타일이 반복되므로 정렬된 흐름이 강해진다. 0.2나 0.8처럼 한쪽에 치우친 값을 쓰면 한 방향이 자주 나타나면서 다른 방향이 그 흐름을 꺾는다. 특정 확률이 항상 더 아름답다는 기준은 없다. 관객이 반복을 빨리 알아보게 할지, 오래 따라가게 할지가 선택 기준이다.

다음에는 cell을 60으로 바꾼다. 실제 실행에서 가로 16칸, 세로 9칸, 총 144개의 큰 타일로 바뀌는 것을 확인했다. 선 굵기도 cell * weight로 계산하므로 같은 비율을 유지한다. 작은 타일은 화면 전체를 질감으로 읽게 하고, 큰 타일은 한 곡선의 방향 전환을 눈에 띄게 한다. 이 화면 크기에서 칸이 정확히 맞도록 예제 비교에는 30과 60을 사용한다. 나누어떨어지지 않는 크기를 쓰면 가장자리 타일이 잘릴 수 있다.

타일 크기를 바꾸면 칸 수와 난수가 배정되는 위치도 바뀐다. 같은 시드라고 해서 기존 경로를 그대로 확대하는 것은 아니다. 같은 배치를 크게 보고 싶다면 캔버스와 타일 크기를 같은 비율로 늘려야 한다. 작업을 비교할 때 시드 숫자만 적지 말고 화면 크기, 타일 크기, 확률과 선 굵기 비율을 함께 기록하자.

weight를 바꾸면 밝은 선이 차지하는 면적이 달라진다. 기본값 0.16을 낮추면 바탕이 많이 드러나고, 높이면 선 사이의 어두운 공간이 좁아진다. 특히 큰 화면에 투사할 때는 가까이에서 보는 선의 매끈함과 멀리서 읽히는 밀도가 다를 수 있다. 이 글에서는 실제 전시장 투사를 검증하지 않았다. 출력할 공간이 있다면 몇 가지 설정을 같은 크기로 띄워 보고 관람 위치에서 고르는 과정이 필요하다.

AI에게 마지막으로 요청할 일은 선택한 화면을 다듬는 방법일 수도 있다. 선택한 화면을 보여 주고 "연결 위치와 시드는 유지한 채 선의 밀도만 낮출 방법"을 물을 수 있다. 제안이 오면 바뀐 변수와 결과를 나란히 확인한다. 이 작품에서 작가가 결정하는 것은 곡선을 매번 손으로 그리는 동작보다, 어떤 연결을 유지하고 어느 정도의 우연을 남길지에 가깝다.