아래 예제는 AEUScripts .aeu용이다. 각 코드블록을 표시된 파일명으로 저장한다. TypeScript와 XML은 빌드한 뒤 실행하고, 배포 시 예제 ID를 자신의 namespace로 바꾼다.
일반 창과 modeless dialog
counter.aeu. Common에서 생성 파일을 실행한다. 숫자만 클로저에 보관하며 AE 프로젝트를 수정하지 않는다. 본문이 반환되어도 콜백은 유지된다. 모든 창을 닫아야 세션이 끝난다.
//@ID com.example.counter-window
//@NAME 'Counter window'
//@TYPE script
const view = ui.createWindow({
id: 'counter', title: 'Counter', width: 360, height: 240,
content: ui.parse(`<column padding="10" gap="8">
<label id="count" text="Count: 0"/>
<button id="increment" text="Count"/>
<button id="help" text="About"/>
<button id="close" text="Close counter"/>
</column>`)
});
let count = 0;
let helpOpen = false;
view.get('increment', 'button').on('click', () => {
view.get('count', 'label').text = `Count: ${++count}`;
});
view.get('help', 'button').on('click', () => {
if (helpOpen) return;
const help = ui.createDialog({
id: 'help', title: 'About', width: 360, height: 160,
content: ui.parse(`<column padding="10" gap="8">
<label text="This is a modeless AEUScripts dialog."/>
<button id="close" text="Close"/>
</column>`)
});
help.get('close', 'button').on('click', () => help.close());
help.onClose(() => { helpOpen = false; });
help.show();
helpOpen = true;
});
view.get('close', 'button').on('click', () => view.close());
view.onClose(() => console.log('Counter closed.'));
view.show();
return 'Callbacks remain active after Run.';
TypeScript
복사
동작 확인: Count가 증가하는지, About 창을 닫은 후 다시 열리는지, Counter와 About을 모두 닫은 뒤 세션이 정리되는지 확인한다.
텍스트 생성 도킹 패널
titles.aeu와 titles.aeui.xml을 같은 폴더에 저장한다. Build Current Script 후 생성 .aeu를 Panels에 등록하고 새 ID이면 AE를 재시작한다. 초기화는 UI만 구성하고 Create 클릭마다 comp를 다시 조회한다.
titles.aeu
//@ID com.example.title-panel
//@NAME 'Title Panel'
//@DESC 'Create text at a chosen position.'
//@VERSION 1.0.0
//@TYPE panel
const view = ui.createPanel({
id: 'titles', title: 'Title Panel',
content: ui.loadXML('titles.aeui.xml')
});
function updatePreview(): void {
const x = view.get('x', 'number').value;
const y = view.get('y', 'number').value;
view.get('preview', 'label').text = `Position: ${x}, ${y}`;
}
view.get('x', 'number').on('input', updatePreview);
view.get('y', 'number').on('input', updatePreview);
view.get('create', 'button').on('click', () => {
const comp = ae.project.activeComp;
if (!comp) {
view.get('status', 'label').text = 'Open a composition first.';
return;
}
const text = view.get('title', 'input').value;
if (!text.trim()) {
view.get('status', 'label').text = 'Enter a title first.';
return;
}
const position: ae.Position = [
view.get('x', 'number').value,
view.get('y', 'number').value
];
const layer = comp.layers.addText(text);
layer.position = position;
view.get('status', 'label').text = 'Created. AE Undo reverses this click.';
});
updatePreview();
view.show();
TypeScript
복사
titles.aeui.xml
<column gap="8" padding="10">
<panel text="New text layer" orientation="column" gap="6">
<label text="Title"/>
<input id="title" value="Hello AEUScripts"/>
<group orientation="column" gap="4">
<label text="X position"/>
<number id="x" value="320" min="-10000" max="10000" step="1" precision="1"/>
<label text="Y position"/>
<number id="y" value="240" min="-10000" max="10000" step="1" precision="1"/>
</group>
<label id="preview" text="Position: 320, 240"/>
</panel>
<button id="create" text="Create text"/>
<label id="status" text="Ready"/>
</column>
XML
복사
동작 확인: comp 없음/빈 제목 안내, number 클릭 편집·드래그, 반복 Create, 클릭 한 번당 Undo, XML 변경 후 재빌드·Restart. number 조작은 UI 미리 보기만 바꾸며 기존 레이어를 이동하지 않는다. 각 Create는 새 레이어를 생성한다.
슬라이더와 체크박스·드롭다운
controls.aeu. 빈 트랙 클릭/드래그와 최신 값의 표시, 체크박스, 드롭다운 change 이벤트를 확인하는 일반 창 예제다.
//@ID com.example.controls
//@NAME 'Controls example'
//@TYPE script
const view = ui.createWindow({
id: 'controls', title: 'Controls',
content: ui.parse(`<column gap="8" padding="10">
<checkbox id="enabled" text="Enable amount" checked="true"/>
<slider id="amount" min="0" max="100" value="25"/>
<select id="mode" value="a">
<option value="a" text="Mode A"/>
<option value="b" text="Mode B"/>
</select>
<label id="status" text="Ready"/>
</column>`)
});
function refresh(): void {
const amount = view.get('amount', 'slider').value;
const mode = view.get('mode', 'select').value;
view.get('status', 'label').text = `Amount ${amount}, mode ${mode}`;
}
view.get('amount', 'slider').on('input', refresh);
view.get('amount', 'slider').on('change', () => {
console.log('Committed', view.get('amount', 'slider').value);
});
view.get('mode', 'select').on('change', refresh);
view.get('enabled', 'checkbox').on('change', event => {
view.get('amount', 'slider').enabled = event.target.checked;
});
refresh();
view.show();
TypeScript
복사
증상별 점검
•
TypeScript 구문 오류 — AE에 원본을 넣었는지 확인. Build 후 .aeuscript/*.aeu 실행
•
저장했는데 이전 코드가 실행됨 — 빌드 성공 여부와 실행 경로 확인. 실패하면 이전 산출물이 유지됨
•
XML을 고쳤는데 UI가 그대로 — XML 저장 → 원본 빌드 → 패널 Restart
•
새 패널이 Window 메뉴에 없음 — ID/TYPE panel, Panels 등록, 새 ID 등록 후 AE 재시작
•
일반 Run에서 createPanel 오류 — Panels 등록 또는 Developer의 Preview UI script 경로 사용
•
패널 초기화 중 AE 접근 오류 — activeComp 조회와 AE 변경을 이벤트 콜백 안으로 이동
•
이전 Layer/Property가 무효 — 이벤트 간 AE wrapper 보관 여부 확인. 현재 API로 기존 레이어 재검색은 불가
•
Timed out / Stopped — 원인을 해결하고 Run/Restart. UI 콜백은 250 ms; native 호출은 강제 중단 불가
•
에러 후 일부 레이어가 남음 — transaction은 rollback이 아님. AE Undo 사용
•
오류 위치 매핑 거부 — 원본/XML/생성물 일치 여부 확인 후 재빌드·재실행
•
좁은 dock에서 컨트롤 잘림 — 고정 폭 합과 orientation 확인. 자동 wrap/축소 배치 없음
•
재시작 후 입력값이 초기화됨 — JS/UI 상태 자동 직렬화는 미지원. workspace 배치 복원과 별개
부동 창의 입력/IME·AE shortcut은 추가 실기 검증 범위다. AE 단축키가 반응하지 않으면 AE 기본 패널을 클릭해 포커스를 확인한다. 자동화 도구의 창 활성화 문제와 실제 사용자 입력 오류를 구분한다.
배포 전 확인
•
활성 comp 없음과 정상 comp에서 결과가 모두 이해 가능한가.
•
반복 이벤트에서 새로운 AE wrapper를 조회하는가.
•
레이어 생성·변경이 한 번의 Undo로 되돌아가는가.
•
Stop/Restart/Close 후 다시 사용할 수 있는가.
•
작은 도킹 폭과 원하는 입력·숫자 범위에서 조작 가능한가.
•
새 도킹 ID는 AE 재시작 후 정상 등록되고, 기존 ID는 업데이트에도 유지되는가.
예제 검증 범위
가이드 전체의 실행 가능한 예제 7개는 2026-10-03 공개 타입과 실제 VS Code 확장 빌드 엔진으로 타입·메타데이터·XML·코드 생성 검사를 모두 통과했다. 이 검사는 After Effects 실기 검증과 다르다. 이번 문서 작성 중 예제를 실제 AE에서 실행하지는 않았다.
근거
skills/aeuscripts-development/references/examples.md, examples/dock-ui/, examples/phase56/, docs/QUICKSTART.md, docs/SCRIPT_UI_API.md 및 공개 타입.




