CSS 애니메이션 워크릿 API

W3C 최초 공개 워킹 드래프트,

이 버전:
https://www.w3.org/TR/2019/WD-css-animation-worklet-1-20190625/
최신 공개 버전:
https://www.w3.org/TR/css-animation-worklet-1/
에디터스 드래프트:
https://drafts.css-houdini.org/css-animationworklet-1/
피드백:
public-houdini@w3.org 제목에 “[css-animation-worklet] … 메시지 주제 …” 포함 (아카이브)
이슈 추적:
명세 내 인라인
GitHub 이슈
에디터:

요약

Animation Worklet API는 스크립트로 애니메이션을 생성하여 애니메이션 효과 집합을 제어할 수 있는 방법을 제공합니다. 이 API는 사용자 에이전트가 이러한 애니메이션을 별도의 스레드에서 실행함으로써 메인 스레드와 분리된 성능을 어느 정도 보장할 수 있도록 설계되었습니다.

이 문서의 상태

이 섹션은 출판 시점에서 이 문서의 상태를 설명합니다. 다른 문서가 이 문서를 대체할 수 있습니다. 현재 W3C 출판물과 기술 보고서의 최신 버전 목록은 W3C 기술 보고서 색인 https://www.w3.org/TR/에서 확인할 수 있습니다.

이 문서는 최초 공개 워킹 드래프트입니다.

최초 공개 워킹 드래프트로서 출판된다고 해서 W3C 회원의 지지를 의미하지는 않습니다. 이 문서는 초안이며 언제든지 업데이트, 교체 또는 폐기될 수 있습니다. 진행 중인 작업 이외의 용도로 인용하는 것은 적합하지 않습니다.

GitHub Issues에서 이 명세에 대한 논의를 우선적으로 진행합니다. 이슈를 등록할 때는 제목에 “css-animation-worklet”을 포함하여, 가능하면 다음과 같이 작성해 주세요: “[css-animation-worklet] …의견 요약…”. 모든 이슈와 의견은 아카이브에 저장됩니다.

이 문서는 CSS 작업 그룹에서 작성되었습니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 그룹 산출물과 관련된 공개 특허 공개 목록을 유지합니다. 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 개별적으로 특정 특허가 필수 청구를 포함한다고 판단하는 경우, W3C 특허 정책 6항에 따라 정보를 공개해야 합니다.

이 문서는 2019년 3월 1일 W3C 프로세스 문서에 의해 관리됩니다.

1. 소개

이 섹션은 규범적인 내용이 아닙니다.

이 문서는 웹 애니메이션의 확장성을 제공하고 웹에서 고성능 상호작용 프로시저 애니메이션을 가능하게 하는 새로운 프리미티브를 소개합니다. 자세한 동기와 근거는 [explainer][principles]를 참고하세요.

Animation Worklet API는 스크립트를 통해 애니메이션을 생성하고 애니메이션 효과 집합을 제어할 수 있는 방법을 제공합니다. 이 API는 사용자 에이전트가 이러한 애니메이션을 별도의 스레드에서 실행함으로써 메인 스레드와 분리된 성능을 어느 정도 보장할 수 있도록 설계되었습니다.

1.1. Web Animations API와의 관계

이 섹션은 규범적인 내용이 아닙니다.

Animation Worklet 실행 컨텍스트 내에서 동작하는 애니메이션은 메인 자바스크립트 실행 컨텍스트에서 Web Animations 명세의 Animation 인터페이스를 노출합니다. 즉, 동일한 Web Animation API를 사용하여 메인 스레드에서 제어 및 검사할 수 있습니다.

2. 애니메이션 워크릿

Animation WorkletWorklet 으로, 커스텀 애니메이션과 관련된 모든 클래스를 담당합니다. worklet은 animationWorklet 속성을 통해 접근할 수 있습니다.

animationWorkletworklet 전역 스코프 타입AnimationWorkletGlobalScope입니다.

AnimationWorkletGlobalScopeanimationWorklet의 전역 실행 컨텍스트를 나타냅니다.

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

3. 애니메이터

Animator는 애니메이션 스레드에서 실행 중인 애니메이션 인스턴스를 나타냅니다. 애니메이터는 고유한 이름으로 식별되며, 현재 입력 시간에 따라 키프레임 효과가 어떻게 진행될지 결정합니다. Animator 인스턴스는 AnimationWorkletGlobalScope 내에 존재하며 각각 WorkletAnimation 인스턴스와 연결됩니다. 애니메이터는 WorkletAnimation 을 생성할 때만 인스턴스화됩니다.

두 가지 애니메이터 타입이 지원됩니다: StatelessAnimatorStatefulAnimator 로, 각각 다른 상태 관리 전략을 제공합니다.

3.1. StatelessAnimator 인터페이스

이 인터페이스는 상태를 가지지 않는 애니메이터를 나타냅니다. 이 타입의 애니메이터는 인스턴스 또는 전역 스코프에 저장된 로컬 상태에 의존하지 않습니다. StatelessAnimator 의 animate 함수는 입력이 같으면 항상 동일한 출력을 반환하는 순수 함수로 취급할 수 있습니다.

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};
클래스 예시는 다음과 같습니다.
class FooAnimator extends StatelessAnimator {
    constructor(options) {
        // 새로운 애니메이터가 인스턴스화될 때 호출됩니다.
    }
    animate(currentTime, effect) {
        // 애니메이션 프레임 로직을 여기에 작성합니다.
    }
}

참고: 상태가 없기 때문에 애니메이션 워크릿은 여러 애니메이션 프레임을 병렬로 생성하거나 매우 저렴하게 해제 및 설정을 수행하는 등 최적화를 할 수 있습니다. 이러한 최적화를 위해 StatelessAnimator 사용을 적극 권장합니다.

3.2. StatefulAnimator 인터페이스

이 인터페이스는 상태를 가지는 애니메이터를 나타냅니다. 이 애니메이터는 로컬 상태를 가질 수 있으며, 애니메이션 워크릿은 해당 인터페이스의 요구 사항을 준수하는 한 이 상태를 유지함을 보장합니다.

Animation worklet 은 서로 다른 스레드 또는 프로세스에 걸쳐 존재할 수 있는 WorkletGlobalScope 집합을 관리합니다. 애니메이션 워크릿은 리소스 절약을 위해 전역 스코프를 일시적으로 종료하거나(예: 리소스 절약 목적), 실행 중인 animator instance를 다른 전역 스코프로 이동시킬 수 있습니다(예: 효과가 특정 스레드에서만 변경 가능한 경우). 애니메이션 워크릿은 상태를 유지해야 하는 stateful animator 인스턴스의 상태가 다른 전역 스코프로 재생성되어도 유지됨을 보장합니다.

상태 유지 기본 메커니즘은 애니메이션 워크릿이 state 함수를 통해 노출된 로컬 상태를 스냅샷으로 저장한 뒤, 나중에 잠재적으로 다른 전역 스코프에서 인스턴스가 재생성될 때 해당 객체를 생성자에 전달하여 상태를 복원하는 것입니다. 애니메이터 인스턴스 마이그레이션 알고리즘은 이 과정을 상세히 설명합니다.

사용자가 정의한 stateful animator는 필수 계약을 준수해야 하며, 즉 state 함수가 구조화 직렬화 알고리즘으로 직렬화할 수 있는 상태 객체를 반환해야 하고, 동일한 객체가 생성자에 전달되면 상태를 복원할 수 있어야 합니다.

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};
클래스 예시는 다음과 같습니다.
class BarAnimator extends StatefulAnimator {
    constructor(options, state) {
      // 새로운 애니메이터가 인스턴스화될 때(최초 또는 재생성 시) 호출됩니다.
      this.currentVelocity  = state ? state.velocity : 0;
    }
    animate(currentTime, effect) {
        // 애니메이션 프레임 로직을 작성할 때 this.currentVelocity를 사용할 수 있습니다.
        this.currentVelocity += 0.1;
    }
    state() {
      // 반환 객체는 구조화 복제 알고리즘으로 직렬화 가능해야 합니다.
      return {
        velocity: this.currentVelocity;
      }
    }
}

3.3. 애니메이터 정의

애니메이터 정의는 작성자가 정의한 커스텀 애니메이션을 AnimationWorkletGlobalScope에서 필요에 따라 설명하는 구조체입니다. 구성 요소는 다음과 같습니다:

3.4. 애니메이터 정의 등록

AnimationWorkletGlobalScope에는 애니메이터 이름-정의 맵이 있습니다. 이 맵은 registerAnimator(name, animatorCtor) 호출 시 채워집니다.
[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);

registerAnimator(name, animatorCtor) 메서드가 AnimationWorkletGlobalScope에서 호출되면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. name이 유효한 <ident>가 아니면, throw를 통해 TypeError를 발생시키고 모든 단계를 중단합니다.

  2. name애니메이터 이름-정의 맵의 키로 존재하면, throw를 통해 NotSupportedError를 발생시키고 모든 단계를 중단합니다.

  3. IsConstructor(animatorCtor) 결과가 false이면, throw를 통해 TypeError를 발생시키고 모든 단계를 중단합니다.

  4. prototypeGet(animatorCtor, "prototype")의 결과로 설정합니다.

  5. SameValue(prototype, StatelessAnimator) 결과가 true라면 statefulfalse로 설정하고, 그렇지 않으며 SameValue(prototype, StatefulAnimator) 결과가 true라면 statefultrue로 설정합니다. 둘 다 아니면 throw를 통해 TypeError를 발생시키고 모든 단계를 중단합니다.

  6. animateValueGet(prototype, "animate")의 결과로 설정합니다.

  7. animate변환하여 animateValueFunction 콜백 함수 타입으로 변환합니다. 예외가 발생하면 예외를 다시 던지고 모든 단계를 중단합니다.

  8. definition을 새 애니메이터 정의로 생성합니다:

  9. (name - definition) 키-값 쌍을 애니메이터 이름-정의 맵에 추가합니다.

4. 애니메이터 인스턴스

애니메이터 인스턴스구조체로, AnimationWorkletGlobalScope에서 완전히 실현된 커스텀 애니메이션 인스턴스를 설명합니다. 이 인스턴스는 애니메이터 정의에 대한 참조를 가지며, 애니메이션 효과나 타임라인 등 인스턴스별 상태를 소유합니다. 구성 요소는 다음과 같습니다:

상태 기반 애니메이터 인스턴스애니메이터 인스턴스 중 해당 애니메이터 정의stateful 플래그true인 경우입니다.

4.1. 애니메이터 인스턴스 생성

애니메이터 인스턴스AnimationWorkletGlobalScope에 존재합니다.

AnimationWorkletGlobalScope에는 애니메이터 인스턴스 집합이 있습니다. 이 집합은 사용자 에이전트가 AnimationWorkletGlobalScope 스코프에서 새로운 애니메이터 인스턴스를 생성할 때 채워집니다. 각 애니메이터 인스턴스는 문서 스코프의 워크릿 애니메이션에 대응됩니다.

새 애니메이터 인스턴스 생성을 위해 name, timeline, effect, serializedOptions, serializedState, workletGlobalScope가 주어졌을 때, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. definitionworkletGlobalScope애니메이터 이름-정의 맵에서 name으로 조회합니다.

    definition이 존재하지 않으면 다음 단계를 중단합니다.

  2. animatorCtordefinition클래스 생성자로 설정합니다.

  3. optionsStructuredDeserialize(serializedOptions)의 결과로 설정합니다.

  4. stateStructuredDeserialize(serializedState)의 결과로 설정합니다.

  5. animatorInstanceanimatorCtor를 인수 «options, state»로 생성한 결과로 설정합니다. 예외가 발생하면 예외를 다시 던지고 모든 단계를 중단합니다.

  6. animatorInstance에 다음을 설정합니다:

  7. animatorInstanceworkletGlobalScope애니메이터 인스턴스 집합에 추가합니다.

4.2. 애니메이터 실행

사용자 에이전트가 새로운 애니메이션 프레임을 생성하려 할 때, 애니메이터 인스턴스 중 연결된 애니메이션 요청 플래그frame-requested인 경우, 사용자 에이전트는 해당 프레임에서 애니메이터 실행반드시 수행해야 합니다.

참고: 사용자 에이전트는 모든 시각적 프레임에서 애니메이션을 실행할 필요가 없습니다. 애니메이션 프레임 생성을 이후 프레임까지 지연시키는 것도 허용됩니다. 이는 사용자 에이전트가 정책에 따라 다른 서비스 수준을 제공할 수 있도록 해줍니다.

사용자 에이전트가 workletGlobalScope에서 애니메이터 실행을 원할 때, workletGlobalScope의 모든 애니메이터 인스턴스를 반복합니다. 각 instance에 대해 사용자 에이전트는 다음을 반드시 실행해야 합니다:

  1. animatorNameinstance애니메이터 이름으로 설정합니다.

  2. definitionworkletGlobalScope애니메이터 이름-정의 맵에서 animatorName으로 조회합니다.

    definition이 존재하지 않으면 다음 단계를 중단합니다.

  3. instance애니메이션 요청 플래그frame-current이거나 instance의 효과가 현재 프레임의 시각적 뷰포트에서 보이지 않을 경우, 사용자 에이전트는 이후 단계를 중단할 수 있습니다.

    사용자 에이전트가 느린 애니메이터 인스턴스 실행을 생략할 권한을 명확히 부여하는 것을 고려하세요.

  4. animateFunctiondefinitionanimate 함수로 설정합니다.

  5. currentTimeinstance애니메이터 현재 시간으로 설정합니다.

  6. effectinstance애니메이터 효과로 설정합니다.

  7. animateFunction을 인수 «currentTime, effect»로, instance콜백 this 값으로 하여 호출합니다.

참고: 비효율적이지만, 사용자 에이전트가 같은 프레임에서 애니메이터 실행을 여러 번 수행하는 것도 허용됩니다.

animateFunction에서 예외가 발생한 경우 동작을 명확히 해야 합니다. 최소한 키프레임의 localTime 값이 무시되어 잘못된 부분적 업데이트를 방지한다는 문구가 있어야 합니다.

4.3. 애니메이터 인스턴스 제거

애니메이터 인스턴스 제거를 위해 instanceworkletGlobalScope가 주어지면 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. instanceworkletGlobalScope애니메이터 인스턴스 집합에서 제거합니다.

4.4. 애니메이터 인스턴스 마이그레이션

마이그레이션 과정은 상태 기반 애니메이터 인스턴스가 로컬 상태를 잃지 않고 다른 WorkletGlobalScope로 이동할 수 있도록 해줍니다.

애니메이터 인스턴스 마이그레이션을 위해, WorkletGlobalScope 간에 instance, sourceWorkletGlobalScope, destinationWorkletGlobalScope가 주어지면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. serializedState를 undefined로 설정합니다.

  2. 작업 큐에 태스크 추가sourceWorkletGlobalScope에서 다음 단계가 실행되도록 추가합니다:

    1. animatorNameinstance애니메이터 이름을 할당합니다.

    2. definitionsourceWorkletGlobalScope애니메이터 이름-정의 맵에서 animatorName으로 조회합니다.

      definition이 존재하지 않으면 다음 단계를 중단합니다.

    3. statefuldefinitionstateful 플래그로 설정합니다.

    4. statefulfalse이면 다음 단계를 중단합니다.

    5. stateFunction

    6. statestateFunction을 instance콜백 this 값으로 호출한 결과로 설정합니다. 예외가 발생하면 예외를 다시 던지고 다음 단계를 중단합니다.

    7. serializedStateStructuredSerialize(state) 결과로 설정합니다. 예외가 발생하면 다음 단계를 중단합니다.

    8. 애니메이터 인스턴스 제거 절차를 instance, sourceWorkletGlobalScope와 함께 실행합니다.

  3. 위 작업이 완료될 때까지 대기합니다. 태스크가 중단되면 이후 단계를 중단합니다.

  4. 작업 큐에 태스크 추가destinationWorkletGlobalScope에서 다음 단계가 실행되도록 추가합니다:

    1. 새 애니메이터 인스턴스 생성 절차를 다음 인수로 실행합니다:

애니메이터 state getter에서 예외가 발생하면 사용자 에이전트는 해당 애니메이터를 제거하지만 다시 생성하지 않습니다. 즉, 해당 애니메이터 인스턴스는 효과적으로 삭제됩니다.

4.5. 애니메이션 프레임 요청

애니메이터 인스턴스는 연관된 애니메이션 요청 플래그를 가집니다. 반드시 frame-requested 또는 frame-current여야 하며, 초기값은 frame-current입니다. 상황에 따라 애니메이션 요청 플래그frame-requested로 설정될 수 있습니다. 예시는 다음과 같습니다:

§4.2 애니메이터 실행에서는 애니메이터의 애니메이션 요청 플래그frame-current로 리셋합니다.

5. Web Animations 통합

5.1. 워크릿 애니메이션

워크릿 애니메이션애니메이션의 일종으로, 애니메이션 재생을 애니메이터 인스턴스에 위임합니다. 해당 애니메이터 인스턴스의 생명주기와 재생 상태를 제어합니다.

애니메이션이므로, 워크릿 애니메이션애니메이션 효과타임라인을 가집니다. 하지만, 일반 애니메이션과 달리 워크릿 애니메이션의 현재 시간은 애니메이션 효과의 local time(inherited time 경유)에 직접적으로 영향을 주지 않습니다. 대신 연관된 애니메이터 인스턴스가 애니메이션 효과의 local time을 직접 제어합니다. 즉, 타임라인의 현재 시간이 애니메이션 결과를 완전히 결정하지 않습니다.

워크릿 애니메이션Animation 인터페이스에 추가로 다음 속성을 가집니다:

Overview of the WorkletAnimation timing model.
WorkletAnimation 타이밍 모델 개요.

애니메이션 현재 시간이 애니메이터 인스턴스에 입력되고, 해당 인스턴스가 애니메이션 효과를 위한 local time 값을 생성합니다. 애니메이터 인스턴스가 병렬 글로벌 스코프에서 실행되는 경우, 구현체는 local time 값을 이용해 최종 효과 값을 산출하고 시각적 업데이트를 병렬로 수행할 수도 있습니다.

5.2. 워크릿 애니메이션 생성

[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
        readonly attribute DOMString animatorName;
};

WorkletAnimation(animatorName, effects, timeline, options)

다음 절차에 따라 새로운 WorkletAnimation 객체를 생성합니다.

  1. workletAnimation을 새로운 WorkletAnimation 객체로 설정합니다.

  2. workletAnimationtimeline을 새로운 타임라인으로 전달하여 애니메이션의 타임라인 설정 절차를 실행합니다. timeline 인수가 제공되지 않은 경우, 문서 기본 타임라인DocumentWindow현재 글로벌 객체에 따라 전달합니다.

  3. 아래 조건 중 처음으로 일치하는 결과에 따라 effect를 설정합니다.

    만약 effectsAnimationEffect 객체라면,

    effect를 effects로 설정합니다.

    effects리스트 형태의 AnimationEffect 객체라면,

    effect를 새로운 WorkletGroupEffect 객체로 설정하고, 자식에 effects를 지정합니다.

    그 외의 경우,

    effect를 undefined로 설정합니다.

  4. workletAnimationeffect를 새로운 효과로 전달하여 애니메이션의 대상 효과 설정 절차를 실행합니다.

  5. serializedOptionsStructuredSerialize(options)의 결과로 설정합니다. 예외가 발생하면 다시 던집니다.

  6. workletAnimation직렬화 옵션serializedOptions로 설정합니다.

  7. workletAnimation애니메이션 애니메이터 이름animatorName으로 설정합니다.

5.3. 워크릿 애니메이션 타이밍 모델

이 섹션에서는 워크릿 애니메이션의 타이밍 모델이 다른 애니메이션과 어떻게 다른지 설명합니다.

기존 애니메이션준비됨으로 간주되는 조건에 추가로, 워크릿 애니메이션은 다음 조건이 참일 때에만 준비됨으로 간주됩니다:

§5.1 워크릿 애니메이션에서 설명했듯이, 워크릿 애니메이션현재 시간애니메이션 효과로컬 시간을 결정하지 않습니다. 대신 연결된 애니메이터 인스턴스가 애니메이션 효과의 로컬 시간을 직접 제어합니다. 즉, 애니메이션 효과의 로컬 시간은 병렬 실행 컨텍스트에 있을 수 있는 WorkletGlobalScope 에서 제어됩니다.

위 의미론의 몇 가지 시사점은 다음과 같습니다:

워크릿 애니메이션이 병렬 워크릿 실행 컨텍스트에서 실행되는 경우, 애니메이션 효과의 마지막 알려진 상태가 주기적으로 메인 자바스크립트 실행 컨텍스트로 동기화되어야 합니다. 병렬 워크릿 실행 컨텍스트에서 메인 자바스크립트 실행 컨텍스트로 효과 값의 동기화는 문서 라이프사이클의 일부로 애니메이션 프레임 콜백 실행 전에 반드시 발생해야 합니다. 이 애니메이션 모델의 비동기적 특성 때문에, 메인 자바스크립트 실행 컨텍스트에서 Worklet Animation으로 애니메이션되는 대상 속성을 읽을 때, 사용자에게 보여지는 시각적 프레임에서 사용 중인 값과 비교해 오래된 값을 볼 수 있습니다. 이는 메인 자바스크립트 실행 컨텍스트에서 스크롤 오프셋을 읽을 때 비동기 스크롤의 효과와 유사합니다.

애니메이터 인스턴스가 reverse(), finish(), playbackRate 변경 등으로 애니메이션의 currentTime이 변경될 때 알림을 받을 수 있는 적절한 메커니즘을 마련해야 합니다. 그래야 적절히 반응할 수 있습니다. <https://github.com/w3c/css-houdini-drafts/issues/811>

5.4. 애니메이터 인스턴스와의 상호작용

워크릿 애니메이션은 언제든지 최대 하나의 애니메이터 인스턴스에 대응되며, 현재 대응되는 애니메이터 인스턴스가 없을 수도 있습니다. 워크릿 애니메이션에 대한 애니메이터 인스턴스의 대응 관계는 애니메이션의 재생 상태에 따라 달라집니다.

워크릿 애니메이션의 애니메이터 인스턴스 연결을 위해 workletAnimation이 주어지면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. workletAnimation에 대응되는 애니메이터 인스턴스가 있으면 다음 단계를 중단합니다.

  2. workletGlobalScopeworkletAnimation과 연관된 AnimationWorkletGlobalScope로 설정합니다.

  3. workletGlobalScope에서 새 애니메이터 인스턴스 생성 절차를 실행하도록 태스크를 에 넣고, 아래 인수를 전달합니다:

  4. 절차가 성공하면, 결과 애니메이터 인스턴스workletAnimation과 연결된 것으로 설정합니다.

워크릿 애니메이션의 애니메이터 인스턴스 연결 해제을 위해 workletAnimation이 주어지면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. workletAnimation에 대응되는 애니메이터 인스턴스가 없으면 다음 단계를 중단합니다.

  2. workletGlobalScopeworkletAnimation과 연관된 AnimationWorkletGlobalScope로 설정합니다.

  3. animatorInstanceworkletAnimation의 대응 애니메이터 인스턴스로 설정합니다.

  4. workletGlobalScope에서 애니메이터 인스턴스 제거 절차를 animatorInstanceworkletGlobalScope를 인수로 하여 실행하도록 태스크를 에 넣습니다.

  5. workletAnimation이 대응되는 애니메이터 인스턴스가 없도록 설정합니다.

워크릿 애니메이션의 애니메이터 인스턴스 설정을 위해 workletAnimation이 주어지면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:

  1. 워크릿 애니메이션의 애니메이터 인스턴스 연결 해제 절차를 workletAnimation에 대해 실행합니다.

  2. 워크릿 애니메이션의 애니메이터 인스턴스 연결 절차를 workletAnimation에 대해 실행합니다.

workletAnimation재생 상태대기중, 실행중, 또는 일시정지로 변경되면, 워크릿 애니메이션의 애니메이터 인스턴스 연결 절차를 workletAnimation에 대해 실행합니다.

workletAnimation재생 상태대기 또는 종료됨으로 변경되면, 워크릿 애니메이션의 애니메이터 인스턴스 연결 해제 절차를 workletAnimation에 대해 실행합니다.

workletAnimation에 대해 애니메이션의 대상 효과 설정 절차가 호출되면, 워크릿 애니메이션의 애니메이터 인스턴스 설정 절차를 workletAnimation에 대해 실행합니다.

workletAnimation에 대해 애니메이션의 타임라인 설정 절차가 호출되면, 워크릿 애니메이션의 애니메이터 인스턴스 설정 절차를 workletAnimation에 대해 실행합니다.

5.5. ScrollTimeline

이 섹션은 규범적인 내용이 아닙니다.

ScrollTimeline 은 웹 애니메이션 API에 새롭게 제안된 개념입니다. 이 타임라인은 스크롤 컨테이너의 스크롤 위치에 따라 시간값이 결정됩니다. 워크릿 애니메이션 은 스크롤 타임라인을 가질 수 있어, 스크롤 오프셋에 따라 스크립트 효과를 구동할 수 있습니다.

참고: 입력 접근성: 우리는 스크롤링 외에도 추가적인 사용자 입력(예: 터치/포인터 입력)을 이러한 애니메이션에 노출하는 것에 관심이 있습니다. 이를 통해 저지연, 입력 기반 애니메이션(현재로서는 불가능한)을 만들 수 있기 때문입니다. 올바른 추상화와 메커니즘을 찾기 위해 계속 논의 중입니다.

5.6. WorkletGroupEffect

WorkletGroupEffect그룹 효과의 한 종류로, 자식 효과로컬 시간을 개별적으로 변경할 수 있게 해줍니다.

WorkletGroupEffect애니메이션 효과WorkletAnimation 에 설정되면, 해당 애니메이터 인스턴스자식 효과로컬 시간을 직접 제어할 수 있습니다. 하나의 워크릿 애니메이션으로 여러 효과를 조정할 수 있습니다. 예시는 §8.2 예제 2: 패럴럭스 배경에서 확인할 수 있습니다.

[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // Intended for use inside Animation Worklet scope to drive the effect.
    attribute double localTime;
};

effectlocalTime 속성을 값 t로 설정하려면, 사용자 에이전트는 다음 조건 중 처음 일치하는 것에 따라 동작해야 합니다:

effect가 부모 그룹이 없는 경우,

effect의 로컬 시간을 t로 설정합니다.

effect가 부모 그룹을 가지고 있고, 그 타입이 WorkletGroupEffect인 경우,

effect의 시작 시간을 (부모의 변환된 시간 - t)로 설정합니다. 즉, effect의 로컬 시간은 t가 됩니다.

그 외의 경우

자식 효과의 시간은 부모 그룹만 제어할 수 있음을 알리는 예외를 발생시킵니다.

위 인터페이스는 web-animation-2의 GroupEffect 제안의 보수적인 서브셋만 노출합니다. 대신, web-animation에 대한 델타 명세로 이동되어야 합니다. <https://github.com/w3c/csswg-drafts/issues/2071>

5.7. Effect Stack 및 합성 순서

다른 애니메이션과 마찬가지로, 워크릿 애니메이션효과 스택에 참여합니다. 워크릿 애니메이션은 특정 애니메이션 클래스가 없으므로, 다른 자바스크립트 기반 웹 애니메이션과 동일한 합성 순서를 가집니다.

6. 보안 고려사항

이 기능들로 인해 알려진 보안 문제는 없습니다.

7. 개인정보 보호 고려사항

이 기능들로 인해 알려진 개인정보 문제는 없습니다.

8. 예제

8.1. 예제 1: 트위터 헤더.

트위터 프로필 헤더 효과의 예시로, 두 요소(아바타와 헤더)가 스크롤 오프셋에 맞춰 동기적으로 업데이트됩니다.
// 문서 스코프에서.
<div id='scrollingContainer'>
  <div id='header' style='height: 150px'></div>
  <div id='avatar'><img></div>
</div>

<script>
await CSS.animationWorklet.addModule('twitter-header-animator.js');
const animation = new WorkletAnimation(
    'twitter-header',
    [new KeyframeEffect($avatar,  /* 스크롤 시 크기 축소 */
                    [{transform: 'scale(1)'}, {transform: 'scale(0.5)'}],
                    {duration: 1000, iterations: 1}),
    new KeyframeEffect($header, /* 스크롤 시 투명도 증가 */
                    [{opacity: 0}, {opacity: 0.8}],
                    {duration: 1000, iterations: 1})],
    new ScrollTimeline({
      scrollSource: $scrollingContainer,
      orientation: 'block',
      timeRange: 1000,
      startScrollOffset: 0,
      endScrollOffset: $header.clientHeight}));
animation.play();

// 그룹 효과를 사용하는 이 애니메이션은
// $avatarEl.getAnimations()[0], $headerEl.getAnimations()[0] 등 다양한 핸들에서 접근 가능합니다.

</script>
// AnimationWorkletGlobalScope 내에서.
registerAnimator('twitter-header', class HeaderAnimator extends StatelessAnimator {
  constructor(options) {
    this.timing_ = new CubicBezier('ease-out');
  }

  animate(currentTime, effect) {
    const scroll = currentTime;  // scroll 값은 [0, 1000] 범위

    // 그룹 효과의 각 자식 localTime을 개별적으로 할당하여 제어
    effect.children[0].localTime = scroll;
    effect.children[1].localTime = this.timing_(clamp(scroll, 0, 500));
  }
});

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

8.2. 예제 2: 패럴럭스 배경.

간단한 패럴럭스 배경 예제입니다.
<style>
.parallax {
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0.5;
}
</style>
<div id='scrollingContainer'>
  <div id="slow" class="parallax"></div>
  <div id="fast" class="parallax"></div>
</div>

<script>
await CSS.animationWorklet.addModule('parallax-animator.js');
const scrollTimeline = new ScrollTimeline({
  scrollSource: $scrollingContainer,
  orientation: 'block',
  timeRange: 1000
});
const scrollRange = $scrollingContainer.scrollHeight - $scrollingContainer.clientHeight;

const slowParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_slow, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.4}
);
slowParallax.play();

const fastParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_fast, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.8}
);
fastParallax.play();
</script>
// AnimationWorkletGlobalScope 내부.
registerAnimator('parallax', class ParallaxAnimator extends StatelessAnimator {
  constructor(options) {
    this.rate_ = options.rate;
  }

  animate(currentTime, effect) {
    effect.localTime = currentTime * this.rate_;
  }
});

적합성

문서 관례

적합성 요구 사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 규범적 부분에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” 등의 주요 단어는 RFC 2119에서 설명한 대로 해석되어야 합니다. 하지만 가독성을 위해 이 명세에서는 이러한 단어가 모두 대문자로 표시되지 않습니다.

이 명세의 모든 본문은 명시적으로 비규범적으로 표시된 섹션, 예제, 주석을 제외하고는 모두 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 단어나 class="example"와 같이 규범적 텍스트와 구분되어 소개됩니다. 예시:

이것은 정보 제공용 예제입니다.

정보성 주석은 “참고”라는 단어로 시작하며 class="note"로 규범적 텍스트와 구분되어 표시됩니다. 예시:

참고, 이것은 정보 제공용 주석입니다.

권고는 특별한 주의를 환기시키기 위해 스타일링된 규범적 섹션이며, <strong class="advisement">로 규범적 텍스트와 구분되어 표시됩니다. 예시: UA는 반드시 접근 가능한 대안을 제공해야 합니다.

적합성 클래스

이 명세에 대한 적합성은 세 가지 적합성 클래스로 정의됩니다:

스타일 시트
CSS 스타일 시트.
렌더러
UA로, 스타일 시트의 의미를 해석하여 이를 사용하는 문서를 렌더링합니다.
저작 도구
UA로, 스타일 시트를 작성합니다.

스타일 시트가 이 명세에 적합하려면, 이 모듈에서 정의된 문법을 사용하는 모든 문이 일반 CSS 문법과 각 기능별 개별 문법에 따라 유효해야 합니다.

렌더러가 이 명세에 적합하려면, 스타일 시트를 적절한 명세대로 해석하는 것 외에도, 이 명세에서 정의된 모든 기능을 올바르게 파싱하고 문서를 그에 따라 렌더링해야 합니다. 단, 기기의 한계로 인해 UA가 문서를 올바르게 렌더링하지 못하더라도 이는 UA가 비적합하다는 의미는 아닙니다. (예: UA는 흑백 모니터에서 색상을 렌더링할 필요는 없습니다.)

저작 도구가 이 명세에 적합하려면, 이 모듈에서 정의된 모든 기능별 개별 문법과 일반 CSS 문법에 따라 구문적으로 올바른 스타일 시트를 작성하고, 이 모듈에서 기술한 스타일 시트의 모든 적합성 요구 사항을 충족해야 합니다.

부분 구현

작성자가 향후 호환성 있는 파싱 규칙을 활용하여 대체 값을 지정할 수 있도록, CSS 렌더러는 반드시 사용 가능한 수준의 지원이 없는 모든 at-규칙, 속성, 속성 값, 키워드 및 기타 구문 구조를 무효로 처리하고 적절하게 무시해야 합니다. 특히, 사용자 에이전트는 지원되지 않는 구성 요소 값을 선택적으로 무시하고 한 선언에서 지원되는 값만 적용해서는 안 됩니다: 하나의 값이라도 무효(지원되지 않는 경우 반드시 무효)로 간주되면 CSS는 전체 선언을 무시해야 합니다.

불안정 및 독점 기능 구현

향후 안정적인 CSS 기능과의 충돌을 피하기 위해, CSSWG는 최선의 관행을 따를 것과 불안정 기능 및 독점 확장 구현에 대해 권장합니다.

비실험적 구현

명세가 후보 권고(Candidate Recommendation) 단계에 도달하면, 비실험적 구현이 가능해지며, 구현자는 명세에 따라 올바르게 구현되었음을 입증할 수 있는 모든 CR 수준 기능을 접두사 없이 공개해야 합니다.

CSS의 구현 간 상호운용성을 확립하고 유지하기 위해, CSS 작업 그룹은 비실험적 CSS 렌더러가 W3C에 구현 보고서(필요하다면 해당 구현 보고서에 사용된 테스트케이스도 포함)를 제출한 후 CSS 기능의 접두사 없는 구현을 공개할 것을 요청합니다. W3C에 제출된 테스트케이스는 CSS 작업 그룹의 검토 및 수정 대상이 됩니다.

테스트케이스 및 구현 보고서 제출에 대한 추가 정보는 CSS 작업 그룹 웹사이트 https://www.w3.org/Style/CSS/Test/에서 확인할 수 있습니다. 문의는 public-css-testsuite@w3.org 메일링 리스트로 보내면 됩니다.

색인

이 명세에서 정의된 용어

참고로 정의된 용어

참고 문헌

규범적 참고 문헌

[CSS-TRANSITIONS-1]
David Baron; et al. CSS Transitions. 2018년 10월 11일. WD. URL: https://www.w3.org/TR/css-transitions-1/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2019년 1월 31일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSSOM-1]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). 2016년 3월 17일. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WEB-ANIMATIONS-1]
Brian Birtles; et al. Web Animations. 2018년 10월 11일. WD. URL: https://www.w3.org/TR/web-animations-1/
[WebIDL]
Boris Zbarsky. Web IDL. 2016년 12월 15일. ED. URL: https://heycam.github.io/webidl/
[WORKLETS-1]
Ian Kilpatrick. Worklets Level 1. 2016년 6월 7일. WD. URL: https://www.w3.org/TR/worklets-1/

참고용 참고 문헌

[EXPLAINER]
Animation Worklet Explainer. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/README.md
[PRINCIPLES]
Animation Worklet Design Principles and Goals. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/principles.md

IDL 색인

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};

[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);


[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
        readonly attribute DOMString animatorName;
};


[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // Animation Worklet 스코프 내에서 효과를 구동하기 위해 사용됨.
    attribute double localTime;
};

이슈 색인

사용자 에이전트가 느린 애니메이터 인스턴스 실행을 건너뛰어 성능 저하를 조절할 수 있도록 허용하는 권한을 제공하는 것을 고려하세요.
animateFunction에서 예외가 발생할 때 어떻게 처리되는지 명확히 해야 합니다. 적어도 키프레임의 localTime 값이 무시되어 잘못된 부분적 업데이트를 방지한다는 문구가 있어야 합니다.
애니메이터 인스턴스의 animation currentTime이 reverse(), finish(), playbackRate 변경 등으로 변할 때 알림을 받을 수 있는 적절한 메커니즘을 마련하세요. 그래야 적절히 반응할 수 있습니다. <https://github.com/w3c/css-houdini-drafts/issues/811>
위 인터페이스는 web-animation-2에서 제안된 GroupEffect의 보수적인 부분집합만 노출합니다. 대신 web-animation에 대한 델타 명세로 이동해야 합니다. <https://github.com/w3c/csswg-drafts/issues/2071>