Florilegium은 이미지나 외부 자산 없이 Lua로 꽃잎, 잎, 줄기의 곡선을 계산해 LaTeX 페이지 여백에 수채화풍 꽃 장식을 그리는 패키지임
자동 성장 배치는 줄기가 닿을 수 있는 가장 큰 빈 공간부터 가지와 꽃으로 채우며, 마지막 페이지에서 본문 아래 남은 공간까지 활용함
본문과 연동해 제목이나 지정한 줄 옆에 꽃을 배치하고, 덩굴로 감싼 장식 머리글자와 페이지 진행에 따른 계절 변화도 지원함
페이지 번호 기반 시드로 같은 페이지의 정원을 재현하며, 하나의 기준색에서 OKLCH로 팔레트를 만들어 밝은 색조에서도 색상을 유지함
독립형 PostScript 버전도 제공해 TeX 없이 장식을 계산하고 출력할 수 있지만, 투명도 처리와 난수 결과가 다르고 일부 기능은 지원하지 않음
외부 이미지 없이 그리는 꽃 여백
-
Reddit의 LaTeX 꽃 장식 질문에서 출발했지만, 원본의 제작 방식을 재현하려는 프로젝트는 아님
-
직접 설계한
기본 도형과 무작위 매개변수, 절차적 배치를 조합해 비슷한 모습을 만듦
-
기본 장식은
Delft 블루 수채화풍이며, 페이지를 출력하는 동안 Lua가 모든 꽃잎, 잎, 줄기를 매개변수 곡선으로 계산해 PDF에 직접 기록함
-
이미지, 가져온 경로, 외부 자산을 사용하지 않음
-
하나의 패키지로 두 가지 구성을 제공하며, 두 예제 PDF의 본문 자체가 여백을 그리는 방식을 설명함
florilegium.tex
는 줄기, 잎, 꽃의 위치를 수작업으로 정하고 매개변수를 무작위로 샘플링함. A4와 68mm 여백에 맞춰져 있으며 다른 레이아웃에 자동 적응하지 않음
florilegium-grow.tex
는 탐욕적 공간 채우기로 페이지 레이아웃과 마지막 페이지의 빈 공간에 맞춰 식물을 성장시킴
그리기 엔진과 수채화 기본 도형
ink.lua
가 모든 기하 계산을 수행하고, 페이지당 하나의 리터럴 노드에 PDF 경로 연산자를 기록하므로 TeX는 산술 계산을 하지 않음
-
기본 도형은 아핀 변환을 적용한 로컬 좌표계에서 그리며, TikZ 범위 안에서 호출하면 해당 이동, 회전, 배율을 읽어 적용함
-
가늘어지는 선은 샘플링한 리본이 아니라
오프셋 Bézier 곡선 두 개로 구성함
-
팔레트는 문서의
ink
색상 하나에서 파생되며, OKLCH 보간으로 가장 어두운 선부터 가장 옅은 채색까지 색상을 유지함
- Delft 블루 외에 세피아, 녹색, 진홍색, 보라색, 청록색 등의 예제가 있음
flora.lua
는 수채화 작업 순서를 따라 기본 채색, 곱하기 방식의 어두운 얼룩, 가장자리의 안료 고임, 흰색으로 걷어낸 줄무늬, 가는 잎맥을 차례로 그리며 외곽선은 거의 쓰지 않음
- 기본 도형에는
꽃과 식물, 작은 동물과 장식 요소가 포함됨
- 넓은 꽃잎과 꽃, 기울어진 별 모양 백합, 작은 꽃, 봉오리, 종 모양 꽃, 갈라진 잎과 가장자리가 매끈한 잎을 지원함
- 전갈 꼬리처럼 말린 물망초 취산꽃차례, 가지 달린 잔가지, 산형꽃차례, 덩굴손, 씨앗 머리를 그릴 수 있음
- 나비, 벌, 달팽이, 새와 함께 구릿빛 반짝임, 로제트, 줄기가 머리말 구분선으로 이어지는 담쟁이 잎 장식도 있음
- 모든 기본 도형을 옅은 유령 형태로 그릴 수 있음
수작업 구성과 자동 성장 알고리듬
authored.lua
는 왼쪽 아래 뿌리에서 시작하는 식물을 구성함
- 수작업 제어점을 지나는 줄기 세 개와 페이지 하단을 따라 꼬리말을 이루는 네 번째 줄기를 배치함
- 잎은 줄기의 지정된 비율 위치에 놓이며, 다른 모티프는 줄기에 접선 방향으로 붙고 모티프의 축을 따라 도착하는 가지에 연결돼 모든 꽃을 뿌리까지 추적할 수 있음
grow.lua
는 Wong, Zongker, Salesin의 SIGGRAPH 1998 논문 Computer-Generated Floral Ornament의 아이디어를 따름
-
높이에 따른 부드러운 노이즈로 줄기를 흔들리듯 올리고, 공간이 있는 마디에 잎을 붙임
-
줄기가 닿을 수 있는
가장 큰 빈 원판을 찾고, 그 안에 맞는 모티프를 선택한 뒤 가장 가까운 줄기 지점에서 가지를 뻗음
-
새 가지도 줄기가 되어 다음 성장에 참여함
-
큰 공간을 먼저 채우므로
꽃과 백합이 초반에 놓이고, 중간에는 꽃가지와 잎이 들어가며, 마지막에는 작은 잎과 봉오리, 작은 꽃이 남은 틈을 채움
-
본문의 끝은 같은 실행에서
\pagetotal
로 측정하므로, 마지막 페이지가 짧으면 한 번의 컴파일만으로 본문 아래까지 가지가 자람
본문을 읽고 반응하는 장식
showcase.tex
는 첫 페이지의 봄부터 여름, 마지막 페이지의 가을로 이어지는 예제로 본문 연동 기능을 보여줌
장식 머리글자는 OpenType 글꼴의 윤곽을 꽃잎처럼 채색하고, 덩굴이 글자 획 위아래를 번갈아 지나도록 만듦
- 기본 글꼴은 Latin Modern Bold이며, 공간에 맞춰 잎과 꽃을 배치하고 글자 내부의 빈 공간도 활용함
- 원래 글자를 보이지 않게 조판하므로 문단을 복사할 때도 첫 글자가 유지됨
제목과 지정한 줄 옆에 꽃을 배치할 수 있음
sections
옵션은 번호가 있는 절과 하위 절의 제목 옆에 구릿빛 꽃을 그림
\florilegiumbloom
은 해당 줄 옆에 꽃을 놓으며, 백합 등 원하는 정원의 모티프를 지정할 수도 있음
florilegium.lua
는 제목과 꽃 지정 위치에 보이지 않는 마커 노드를 남기고, 페이지 출력 시 상자를 순회해 높이, 깊이, 실제 적용된 글루 간격을 합산함
- 마커의 페이지 내 높이를 찾은 뒤 잎을 배치하기 전에 해당 줄에 꽃을 먼저 놓으므로, 위치 처리는 한 번의 실행으로 가능함
계절 변화는 위치가 아니라 자라는 모티프를 바꿈
aging
옵션은 첫 페이지의 봉오리와 작고 옅은 잎에서 마지막 페이지의 씨앗 머리, 떨어지는 꽃잎, 일부 구릿빛 잎으로 진행함
- 모티프 선택 가중치를 나이에 따라 바꾸며, 가을의 일부 잎에는
ink
대신 강조색에서 만든 팔레트를 적용함
- 전체 페이지 수가 필요해 두 번 실행해야 하지만, 나이를 직접 지정할 수도 있음
머리글자의 기하 처리와 방문 동물
initial.lua
는 luaotfload의 OpenType 리더에서 글자 윤곽을 Bézier 구간으로 가져옴
-
윤곽을 다각형으로 평탄화해
짝홀 규칙 내부 판정에 사용하고, 글자와 테두리까지의 거리 격자로 꽃이 들어갈 가장 큰 틈을 찾음
-
덩굴은 타일을 가로지르는 Catmull-Rom 곡선이며, 글자와 만날 때 위아래를 번갈아 통과함
-
위로 지나는 부분은 글자 영역으로 클리핑한 뒤 종이색의 얇은 테두리와 함께 다시 그림
-
대부분의 페이지에는
나비와 벌, 주요 줄기를 타는 달팽이가 등장하며, 약 다섯 페이지 중 하나에는 별도 잔가지에 앉은 새가 나타남
-
동물은 독립적인 난수 스트림을 사용하므로
novisitors
로 제외해도 나머지 정원은 그대로 유지됨
재현 가능한 페이지와 성장 애니메이션
시드는 페이지 번호에서 파생되므로 페이지 n은 항상 정원 n을 얻음
-
고정 시드를 직접 지정할 수도 있으며, 이러한 재현성이 문서를 안정적으로 조판할 수 있게 함
-
성장 애니메이션은
페이지 배치 때 한 번 기록함
-
같은 난수 추출을 재현하면서 줄기를 점차 길어지는 부분 경로로, 모티프를 몇 단계의 작은 배율로 함께 그려 둠
-
각 프레임은 등장 시점이 된 조각을 원래의 채색 순서대로 출력함
-
애니메이션에서는 줄기가 먼저 자라고 마디를 지나며 잎이 펴진 뒤, 줄기 끝에 꽃이 생기고 빈 공간 채우기가 이어짐
-
큰 틈은 먼저 천천히, 작은 틈은 나중에 빠르게 채워짐
-
나비와 벌이 날아들고 새가 잔가지에 내려앉으며 달팽이가 줄기를 올라감
-
마지막 프레임은 해당 시드의 정적인 페이지와 정확히 같음
-
시드 6의 예제는 약
45초 분량의 GIF와 MP4로 렌더링할 수 있으며, 설명 모드에서는 선택한 빈 원판을 점선으로 표시함
TeX 없이 실행하는 PostScript 버전
postscript/florilegium.ps
는 자동 성장 여백을 구현한 독립형 파일로, TeX나 다른 파일이 필요 없음
ink.lua
, flora.lua
, grow.lua
의 그리기 코어, 기본 도형, 성장 루프를 프로시저 단위로 이식함
-
Ghostscript나 프린터가 페이지를 해석하면서 꽃잎을 계산하고, 두 페이지의 본문이 구현 방식을 설명함
-
두 페이지 처리에는 약 2.5초가 걸림
-
PostScript의
변환 행렬과 기본 경로 기능이 이동, 회전, 배율, Bézier 곡선을 처리하며, 실행 중 만든 프로시저가 Lua 클로저를 대신함
-
성장 순서와 뒤에서 앞으로 칠하는 순서가 달라
레이어별 기록과 재생이 필요함
pathforall
로 각 채우기와 선을 레이어별 목록에 저장한 뒤 마지막에 재생함
투명도는 Ghostscript 확장에 의존함
-dALLOWPSTRANSPARENCY
가 없거나 프린터로 출력하면, 반투명 채색을 예상 배경색과 미리 혼합해 불투명하게 그림
난수와 텍스트 처리에는 LaTeX 버전과 차이가 있음
-
32비트 정수 연산의 Park-Miller 생성기와 단정밀도 실수를 사용하므로 같은 시드라도 LaTeX 버전과 다른 정원이 나옴
-
자체적으로 Times 글꼴의 두 페이지를 조판하고 제목 위치와 본문 끝을 알아 제목 옆 꽃과 마지막 줄 아래 정원을 지원함
-
장식 머리글자, 애니메이션, 수작업 구성은 지원하지 않음
-
시드와 계절을 지정하거나 동물을 제외할 수 있으며,
시드를 생략하면 시계 값을 사용해 출력할 때마다 새 정원을 만듦
-
Epson 잉크젯에 같은 파일을 두 번 보낸 예제에서는 인쇄 시스템이 작업마다 프로그램을 다시 실행해 서로 다른 정원을 출력함
사용 환경과 라이선스
LuaLaTeX로 일반 문서는 한 번 실행하며 페이지당 약 1초가 걸림
는 페이지 수 계산 때문에 두 번 실행해야 함
- Docker 빌드 환경과 Overleaf 사용 방법도 제공함
TikZ 안에서 기본 도형을 개별 호출할 수 있으며, 현재 범위의 이동, 회전, 배율이 적용됨
- CLAUDE.md에 코드 구조, 조정 가능한 값, 아직 구현하지 않은 아이디어가 정리돼 있음
MIT 라이선스로 배포됨
댓글과 토론