시퀀스 (Sequences)
Griptape Nodes는 번호가 매겨진 파일이 있는 디렉터리를 시퀀스(sequences)로 읽을 수 있습니다. 예를 들어 render.0001.exr, render.0002.exr, … render.0100.exr과 같은 렌더링 출력뿐만 아니라 대화 테이크(take_##.wav), 텍스트 청크(chapter_###.md) 또는 파일 이름의 숫자 키가 항목들을 순서가 지정된 세트로 그룹화하는 모든 것이 해당됩니다. 시퀀스를 인식하는 노드에 경로 또는 패턴(숫자 자리표시자가 있는 파일 이름 또는 리터럴 파일 경로)을 지정하면 엔진이 디스크에서 일치하는 항목을 찾고 공백(간격)을 처리한 후 정수 번호 및 0(zero) 패딩된 문자열 형태가 포함된 항목 목록을 반환합니다.
이 문서에서는 경로/패턴 구문, 누락된 항목을 처리하는 정책, 그리고 패턴을 작성하기 전에 알아두어야 할 규칙을 설명합니다.
패턴 구문
시퀀스 패턴은 항목 번호 자리에 토큰이 있는 파일 이름 형태입니다. 네 가지 토큰 형식이 지원됩니다:
| 토큰 | 자릿수(너비) | 설명 |
|---|---|---|
#### |
4 | 각 #은 한 자리 숫자입니다. ## = 2자리, #### = 4자리 등. |
%04d |
4 | C 스타일 printf 형식입니다. %04d = 4자리 0 패딩. |
@@@@ |
4 | Houdini/RV 스타일입니다. ####와 동일한 의미입니다. |
$F4 |
4 | Houdini 변수 형식입니다. ####와 동일한 의미입니다. |
네 가지 모두 동일하게 작동하므로 파이프라인 규칙에 맞는 것을 선택하세요. 새 템플릿의 경우 DCC 도구 전반에서 가장 널리 이해되는 #### 또는 %04d를 사용하는 것을 권장합니다.
몇 가지 예시:
render.####.exr 항목 5 → render.0005.exr
render.%04d.png 항목 12 → render.0012.png
take_##.wav 항목 7 → take_07.wav
토큰은 항상 파일 이름에 위치합니다. 디렉터리 구성 요소 내부의 토큰(예: render/####/beauty.exr)은 지원되지 않습니다. 숫자는 파일 이름 부분에만 유지하세요.
경로에 시퀀스 토큰이 없는 경우
시퀀스 토큰이 없는 경로(/work/photo.png, {inputs}/poster.png, render.0002.png)는 모호합니다. 이는 다음 중 하나를 의미할 수 있습니다:
- 특정 파일 하나의 리터럴 이름 —
render.0002.png가 바로 원하는 파일인 경우; - 암시적 시퀀스의 한 프레임 — fileseq가 숫자를 확인하고 발견한 모든
render.NNNN.png를 단일 시퀀스로 그룹화하는 경우; - 실수로 누락된 경우 — 아티스트가
####입력을 잊어버렸으므로 명확하게 오류를 발생시켜 수정하도록 하는 경우.
엔진은 NoTokenBehavior(griptape_nodes.common.sequences에 정의됨)를 통해 호출자에게 어떤 해석을 사용할지 묻습니다:
| 값 | 결과 |
|---|---|
SINGLE_FILE (기본값) |
전체 파일 이름을 리터럴로 처리합니다. 파일이 존재하는 경우 1개 항목 시퀀스(first=last=1, padding=0)를 반환하고, 존재하지 않는 경우 빈 결과를 반환합니다. 동일한 디렉터리의 다른 형제 파일은 무시됩니다. 옆에 0001..0005가 있더라도 render.0002.png는 render.0002.png만 반환합니다. |
EXPLORE_SEQUENCE |
fileseq가 파일 이름의 숫자를 암시적 시퀀스 토큰으로 읽도록 허용합니다. render.0002.png는 추론된 render.####.png 시퀀스의 한 프레임이 되며, 검사는 일치하는 모든 형제 파일을 탐색합니다. 다운스트림 도구에서 파일 이름 하나만 제공했지만 전체 테이크를 가져오고자 할 때 유용합니다. |
REJECT |
INVALID_TEMPLATE 오류와 함께 즉시 실패하며 아티스트에게 토큰을 추가하도록 요청하는 메시지를 표시합니다. 아티스트의 의도를 암묵적으로 확장해서는 안 되는 파이프라인을 위한 엄격 모드입니다. |
SINGLE_FILE을 기본값으로 사용하면 "파일 하나를 선택했다"는 직관적인 기대치인 '경로 → 단일 항목 시퀀스' 매핑이 유지됩니다. 암시적 그룹화 동작을 원하는 워크플로는 명시적으로 옵트인합니다.
매크로와의 결합
시퀀스 경로는 프로젝트의 매크로 언어와 함께 작동합니다. 매크로 헤드는 엔진이 디스크에서 올바른 디렉터리를 읽을 수 있도록 내부적으로 해석되지만, 엔진은 사용자가 제공한 형태 그대로 경로를 출력합니다:
입력 : {inputs}/shot_a/render.####.exr
출력 : Sequence(directory="{inputs}/shot_a",
entries=[{path: "{inputs}/shot_a/render.0001.exr"},
{path: "{inputs}/shot_a/render.0002.exr"}, ...])
이를 통해 검사 결과의 이식성이 보장됩니다. {inputs}가 /Volumes/Renders로 해석되는 머신에서 구축된 워크플로는 경로에 여전히 {inputs}가 표시되는 시퀀스를 생성합니다. 이 워크플로를 {inputs}가 C:
enders로 해석되는 머신에서 다시 열어도 정상 작동합니다. 다운스트림의 모든 소비자가 자체 프로젝트를 기준으로 매크로를 새로 해석하기 때문입니다.
일반 절대 경로({...} 세그먼트 없음)는 동일하게 왕복 처리됩니다. /work/render.####.png를 입력하면 /work/render.0001.png를 다시 받게 됩니다.
상대 경로. 선행 /가 없고 매크로 헤드가 없는 경로(예: shot_a/render.####.png)는 프로젝트의 워크스페이스 디렉터리를 기준으로 해석됩니다. 엔진은 목록을 나열하기 전에 워크스페이스 경로를 앞에 추가하므로 shot_a/render.####.png와 {workspace_dir}/shot_a/render.####.png는 동일하게 해석됩니다. 워크플로에 더 자연스럽게 읽히는 형식을 사용하세요.
{...} 내부의 매크로 변수는 시퀀스 토큰과 완전히 분리되어 있으며, 구문을 공유하지 않고 서로 다른 단계에서 해석됩니다.
자릿수(너비) 일치는 엄격하게 적용됨
# 문자의 개수(또는 %0Nd 너비)는 일치시킬 숫자의 정확한 자릿수를 선언합니다. 패턴에 ####가 지정된 경우 엔진은 해당 슬롯에 정확히 4자리 숫자가 있는 파일과 일치시킵니다. 즉 render.0001.exr은 일치하지만 render.001.exr(3자리) 및 render.12345.exr(5자리)은 일치하지 않습니다.
이는 Nuke의 동작 방식과 일치합니다. 시퀀스에 선언된 패딩을 초과하는 숫자가 포함된 경우(예: 4자리 패턴이지만 실제 숫자가 9999를 초과함) 더 넓은 패턴(#####)을 사용하여 캡처하세요.
디렉터리에 서로 다른 패딩 너비를 가진 파일(예: render.0001.png 및 render.001.png)이 모두 포함되어 있는 경우 이들은 별도의 시퀀스로 처리됩니다. 엔진은 선언된 템플릿과 패딩이 일치하는 시퀀스만 일치시키고 다른 시퀀스는 무시합니다.
누락 항목 처리 정책 (Missing-item policies)
실제 시퀀스에는 간격(gap)이 자주 발생합니다. 47번 프레임에서 중단된 렌더링, 다른 테이크만 건너뛰어 저장된 희소 내보내기, 아직 작성되지 않은 챕터 등이 있습니다. 시퀀스를 검사할 때 이러한 간격을 처리하는 정책(policy)을 선택할 수 있습니다:
| 정책 | 결과 |
|---|---|
ABORT |
즉시 실패합니다. [first, last] 내에서 첫 번째 간격이 발견되면 해당 문제 항목 번호를 포함하는 오류가 발생합니다. Sequence는 반환되지 않습니다. |
SPLIT (기본값) |
존재하는 항목의 연속적인 구간(contiguous run)마다 하나의 시퀀스를 생성합니다. 항목 1–5, 8–12, 15가 있는 시퀀스는 세 개의 개별 시퀀스를 생성합니다. |
SKIP |
존재하는 항목만 포함하는 단일 시퀀스를 생성합니다. 간격은 출력에서 제외됩니다(단, 시퀀스의 missing_numbers 세트를 통해 확인 가능). |
FILL_NEAREST |
전체 [first, last] 범위를 포괄하는 단일 시퀀스를 생성합니다. 누락된 각 항목은 가장 가까운 이전 항목의 경로(이전 항목이 없는 경우 가장 가까운 이후 항목)로 채워집니다. |
간격 발생 시 워크플로가 명확하게 실패해야 하는 경우 ABORT를 선택하세요(예: 중단된 렌더링이 자동으로 진행되어서는 안 됨). 간격 구조를 보존하려는 경우 SPLIT을 선택하세요(각 연속 구간 자체가 의미가 있는 경우). 디스크의 실제 상태와 관계없이 단일 희소 시퀀스를 원하는 경우 SKIP을, 단일 조밀 시퀀스를 원하는 경우 FILL_NEAREST를 선택하세요.
도메인별 간격 렌더링은 엔진이 아니라 노드의 역할입니다. 검은색 프레임 자리표시자, 마젠타/노란색 체크보드, 무음 오디오 청크, 빈 텍스트 청크 또는 누락된 항목 대신 합성된 기타 요소를 원할 경우 SKIP으로 검사하고 노드에서 missing_numbers를 순회하여 도메인에 필요한 항목을 렌더링하세요. 엔진은 의도적으로 "이 번호가 디스크에 없음"까지만 처리하고 나머지는 노드가 담당합니다.
하위 집합 자르기 (Subset clipping)
시퀀스를 인식하는 노드는 선택적 start 및 end 범위를 허용합니다. 제공된 경우 검사는 해당 범위로 잘립니다:
start미만 및end초과의 항목은 출력에서 제외됩니다.- 원래 디스크 범위는
discovered_first/discovered_last를 통해 계속 보고되므로 자르기 전에 무엇이 존재했는지 확인할 수 있습니다. - 발견된 범위 밖의 하위 집합 범위는 빈 결과(실패)를 생성합니다.
반환되는 결과 구조
Sequence는 Pydantic 모델입니다. 속성별로 필드를 읽을 수 있습니다(seq.first, seq.entries[0].number). 시퀀스를 다루는 노드는 입력을 type="Sequence"로 선언해야 하며, 엔진은 이름으로 연결의 유효성을 검사합니다.
각 Sequence에는 다음이 포함됩니다:
first/last— 활성 범위 (하위 집합 자르기 적용 후).discovered_first/discovered_last— 하위 집합을 무시하고 디스크에 실제로 존재했던 범위.padding— 선언된 0 패딩 너비 (예:####의 경우 4).pattern— 정규화된 패턴 (예:render.####.exr).directory— 사용자가 제공한 경로의 디렉터리 부분 (매크로를 제공한 경우 매크로 형태, 그렇지 않은 경우 일반 절대 경로).policy— 적용된 정책.entries— 활성 범위의 각 항목당 하나의SequenceEntry. 각 항목의 구성:number— 정수 키 (예: 5).padded_number— 0으로 패딩된 형태 (예:0005).path— 문자열 파일 경로 (제공된 것과 동일한 형태). 매크로 형식 입력은 매크로 헤드가 유지된 채로 반환되며({inputs}/render.0005.exr), 일반 절대 경로는 그대로 반환됩니다(/work/render.0005.exr).FILL_NEAREST상태에서 채워진 간격 항목은 가장 가까운 존재하는 이웃의 경로를 가집니다. 실제 존재하는 항목인지 채워진 항목인지 구분하려면entry.number in seq.present_numbers를 확인하세요.
present_numbers—[first, last]내에서 실제로 디스크에 존재하는 번호 집합.missing_numbers—present_numbers에서 파생됨: 활성 범위 내에서 디스크에 없는 번호 (모든 정책에서 진단용으로 유용함).
의도적으로 지원되지 않는 사례
다음 몇 가지 경우는 의도적으로 제외되었습니다:
- 음수 번호:
render.-0005.exr과 같은 파일은 검사 시 필터링되어 제외됩니다. 제외된 개수는 결과 시퀀스에 보고됩니다. - 디렉터리 구성 요소의 시퀀스 토큰:
render/####/beauty.exr과 같은 패턴은 일치하지 않습니다. 숫자는 파일 이름에 넣어야 합니다. - 다중 토큰 패턴: 둘 이상의 시퀀스 토큰이 있는 템플릿(예:
v##_f####.exr,render.##.##.exr)은 명확한 오류와 함께 검사 시 거부됩니다. 패턴당 단일 토큰을 사용하세요. - 타임코드: 아직 지원되지 않습니다.
기술 배경
시퀀스 처리는 VFX 스타일 프레임 범위 파싱의 사실상 표준 Python 라이브러리인 fileseq를 기반으로 구축되었습니다. 파서 및 숫자 연산 라이브러리로 사용되며, 모든 파일 시스템 나열은 엔진의 요청 버스를 통해 처리되므로 다른 파일 작업에 적용되는 동일한 워크스페이스 권한, 경로 정규화 및 Windows 긴 경로 처리가 여기에도 적용됩니다. fileseq 자체는 전체적으로 "frame(프레임)"이라는 용어를 사용하지만 이는 구현 세부 사항입니다. 공개 API는 이미지뿐만 아니라 번호가 매겨진 파일 이름 시퀀스 전반을 처리할 수 있도록 "items(항목)" 및 "numbers(번호)" 용어를 사용합니다.
공개 진입점: ScanSequencesRequest
검사는 함수를 직접 가져오는 것이 아니라 엔진의 이벤트 버스에서 디스패치됩니다. ScanSequencesRequest(griptape_nodes.retained_mode.events.os_events에 정의됨)를 전송하고 await GriptapeNodes.ahandle_request(...)를 호출합니다. 핸들러는 프로젝트 매크로를 해석하고, 디렉터리 목록을 나열하며, 작업자 스레드에서 fileseq 파싱을 실행하므로 깊은 디렉터리에 대한 오래 걸리는 검사가 이벤트 루프를 차단하지 않습니다.
요청은 단일 path 필드를 받습니다. 예시:
# 매크로 형식 패턴. {inputs} 헤드는 출력된 모든 경로에 보존됩니다.
ScanSequencesRequest(path="{inputs}/shot_a/render.####.exr")
# 일반 절대 경로 패턴. 동일하게 왕복 처리됩니다.
ScanSequencesRequest(path="/work/render.####.png", policy=MissingItemPolicy.SKIP)
# 토큰이 없는 경로. 기본값 `no_token_behavior=SINGLE_FILE`은 정확히 해당 파일을 포함하는
# 1개 항목 시퀀스를 반환합니다(파일이 없으면 빈 결과).
ScanSequencesRequest(path="/work/photo.png")
# 토큰이 없는 경로이지만 암시적 시퀀스의 한 프레임으로 처리하고 일치하는 모든 형제 파일을 탐색합니다.
ScanSequencesRequest(
path="/work/render.0002.png",
no_token_behavior=NoTokenBehavior.EXPLORE_SEQUENCE,
)
# 엄격 모드: 경로에 토큰이 없으면 INVALID_TEMPLATE으로 실패합니다.
ScanSequencesRequest(
path="/work/render.0002.png",
no_token_behavior=NoTokenBehavior.REJECT,
)
# 활성 범위 하위 집합 지정.
ScanSequencesRequest(path="{inputs}/render.####.exr", start_number=10, end_number=50)
성공 시 다음을 포함하는 ScanSequencesResultSuccess가 반환됩니다:
sequences: list[Sequence]— 정책 적용 후 추론된 시퀀스 목록. 모든Sequence.directory및entry.path는 제공된 것과 동일한 경로 형태를 유지합니다(매크로 형식 입력은 매크로 형식으로 출력).has_entries: bool— 하나 이상의 Sequence에 하나 이상의 항목이 있는 경우 true. 오류 없이 정상 실행되었지만 아무것도 찾지 못한 경우는 실패가 아니라has_entries=False인 성공입니다. 빈 결과에 대해 즉시 실패해야 하는 호출자는has_entries를 직접 확인합니다.directory_had_matching_files: bool— 디렉터리 목록에 기본 이름(basename) + 확장자가 대상 형태와 일치하는 파일이 하나 이상 포함되어 있는 경우 true(사전 필터가 무언가를 수락함).has_entries와 결합하여 검사 결과가 빈 이유를 알려줍니다: false는 경로가 잘못되었거나 기본 이름/확장자가 일치하지 않음을 의미하며, true이면서has_entries=False인 경우는 파일은 존재하지만 패딩이 맞지 않거나 활성 하위 집합이 모두 잘라냈음을 의미합니다.discovered_first: int | None/discovered_last: int | None— 하위 집합 자르기가 적용되기 전 디스크에서 추론된 번호의 범위. fileseq가 디렉터리에서 하나 이상의 번호를 추론했을 때마다 채워지며, 목록에 패딩 일치 번호가 없으면None이 됩니다. 호출자가 추측 없이 하위 집합 자르기 사례를 진단할 수 있습니다(예: "90..100을 요청했지만 디스크에는 1..7만 있음").
이 세 가지 진단 필드를 통해 소비자는 result_details 문자열을 일일이 검사하지 않고도 잘못된 경로 / 잘못된 패딩 / 잘못된 범위 사례를 구분할 수 있습니다. 하나 이상의 시퀀스가 있는 경우 각 Sequence 개체의 discovered_first/discovered_last를 확인하는 것이 적절하며, 최상위 필드는 특히 빈 결과 진단을 위한 것입니다.
실패 시 failure_reason으로 SequenceScanFailureReason(INVALID_TEMPLATE, INVALID_BOUNDS, ABORTED_AT_GAP) 또는 OS 계층의 FileIOFailureReason을 포함하는 ScanSequencesResultFailure가 반환됩니다. 실패는 검사를 진행할 수 없는 경우에 발생합니다:
INVALID_TEMPLATE— 경로 문자열을 파싱할 수 없음 (잘못된 매크로 구문, 다중 토큰 패턴, 파일 이름 누락, 해석할 수 없는 매크로 변수 등). 또한 경로에 시퀀스 토큰이 없고no_token_behavior가REJECT인 경우에도 발생합니다.INVALID_BOUNDS—start_number < 0또는end_number < start_number.ABORTED_AT_GAP—ABORT정책 실행 중 활성 범위 내에서 하나 이상의 간격이 발견됨. 실패 시missing_item_numbers: list[int]에 오름차순으로 정렬된 문제 정수 키가 채워지므로, UI 소비자는 아티스트에게 재실행을 반복하게 하지 않고 한 번에 모든 누락 슬롯을 보여줄 수 있습니다.FileIOFailureReason값 — 내부 디렉터리 나열 실패 (디렉터리를 찾을 수 없음, 권한 거부 등). 이는 빈 성공으로 처리되지 않고FileIOFailureReason을 통해 표출됩니다.
노드 수준: fail_on_empty_result
표준 라이브러리의 ScanSequenceNode 및 ScanSplitSequenceNode는 모두 최상위 파라미터로 fail_on_empty_result: bool = True를 제공합니다. true(기본값)인 경우 빈 검사 결과는 위의 필드로 구성된 진단 인식 상태 메시지와 함께 노드를 Failure 제어 흐름 에지로 라우팅합니다. false인 경우 노드는 빈 출력과 함께 성공하며 옵트아웃을 나타내는 상태를 기록합니다(아무것도 찾지 못해도 정상인 검색 워크플로에 적합).
노드 수준: 시퀀스 마커가 없을 때 (When there's no sequence marker)
두 Scan 노드는 축소된 Advanced Sequence Control 그룹 내에서 When there's no sequence marker (e.g., ###) 레이블이 지정된 드롭다운으로 NoTokenBehavior 선택 항목을 제공합니다. 세 가지 옵션은 엔진 열거형에 다음과 같이 매핑됩니다:
| 드롭다운 레이블 | 엔진 값 |
|---|---|
| Treat as a single file (기본값) | SINGLE_FILE |
| Treat as part of a sequence | EXPLORE_SEQUENCE |
| Fail unless a token is present | REJECT |
동일한 드롭다운은 노드 내부의 상대 범위 검색 프로브도 구동하므로(Start at / End at이 Relative …로 설정된 경우), 노드가 오프셋을 탐색한다는 이유만으로 리터럴 파일 경로가 탐색되지 않도록 방지합니다.
라이브러리 및 노드 코드는 기본 스캐너를 직접 가져와서는 안 되며, 요청 버스가 유일한 공개 경로입니다.