SkillAgentSearch skills...

Orbital

🪐 Jetpack Compose Multiplatform library that allows you to implement dynamic transition animations such as shared element transitions.

Install / Use

/learn @skydoves/Orbital
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<h1 align="center">Orbital</h1></br> <p align="center"> <a href="https://devlibrary.withgoogle.com/products/android/repos/skydoves-Orbitary"><img alt="Google" src="https://skydoves.github.io/badges/google-devlib.svg"/></a><br> <a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"/></a> <a href="https://android-arsenal.com/api?level=21"><img alt="API" src="https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat"/></a> <a href="https://github.com/skydoves/Orbital/actions/workflows/android.yml"><img alt="Build Status" src="https://github.com/skydoves/Orbital/actions/workflows/android.yml/badge.svg"/></a> <a href="https://androidweekly.net/issues/issue-525"><img alt="Android Weekly" src="https://skydoves.github.io/badges/android-weekly.svg"/></a> <a href="https://us12.campaign-archive.com/?u=f39692e245b94f7fb693b6d82&id=68710ad80a"><img alt="Kotlin Weekly" src="https://skydoves.github.io/badges/kotlin-weekly.svg"/></a> <a href="https://github.com/skydoves"><img alt="Profile" src="https://skydoves.github.io/badges/skydoves.svg"/></a> </p><br> <p align="center"> 🪐 Jetpack Compose animation library that allows you to implement animations such as shared element transition. This library support Kotlin Multiplatform (Android, iOS, Desktop, macOS, and js) </p><br> <p align="center"> <img src="previews/preview0.gif" width="270"/> <img src="previews/preview1.gif" width="270"/> <img src="previews/preview3.gif" width="270"/> </p> <p align="center"> <img src="previews/preview4.gif" width="270"/> <img src="previews/preview5.gif" width="270"/> </p>

Download

Maven Central

Gradle

Add the dependency below to your module's build.gradle file:

dependencies {
    implementation("com.github.skydoves:orbital:0.4.0")
}

Note: This is an experimental library that demonstrates various animations with Jetpack Compose. Please make sure that your project uses Jetpack Compose 1.5.4, Compose Compiler 1.5.4, and Kotlin 1.9.20.

For Kotlin Multiplatform, add the dependency below to your module's build.gradle.kts file:

sourceSets {
    val commonMain by getting {
        dependencies {
            implementation("com.github.skydoves:orbital:$version")
        }
    }
}

Usage

You can implement three kinds of animations with Orbital: Movement, Transformation, and Shared Element Transition. Basically, you can run animation with Orbital Composable function, which provides OrbitalScope that allows you to create animations.

Transformation

<img src="previews/preview1.gif" width="300px" align="center">

The example below shows how to implement resizing animation with the animateTransformation extension of the OrbitalScope. The rememberContentWithOrbitalScope allows you to create custom animations such as animateTransformation on the OrbitalScope. You can apply the animateTransformation animation to specific Composables and customize its AnimationSpec as seen the below:

  val transformationSpec = SpringSpec<IntSize>(
    dampingRatio = Spring.DampingRatioMediumBouncy,
    stiffness = 200f
  )

  var isTransformed by rememberSaveable { mutableStateOf(false) }
  val poster = rememberContentWithOrbitalScope {
    GlideImage(
      modifier = if (isTransformed) {
        Modifier.size(300.dp, 620.dp)
      } else {
        Modifier.size(100.dp, 220.dp)
      }.animateTransformation(this, transformationSpec),
      imageModel = ItemUtils.urls[0],
      contentScale = ContentScale.Fit
    )
  }

  Orbital(
    modifier = Modifier
      .clickable { isTransformed = !isTransformed }
  ) {
    Column(
      Modifier.fillMaxSize(),
      horizontalAlignment = Alignment.CenterHorizontally,
      verticalArrangement = Arrangement.Center
    ) {
      poster()
    }
  }

Movement

<img src="previews/preview2.gif" width="300px" align="center">

The example below shows how to implement movement animation with the animateMovement extension of the OrbitalScope. The rememberContentWithOrbitalScope allows you to create custom animations such as animateMovement on the OrbitalScope. You can apply the animateMovement animation to specific Composables and customize its AnimationSpec as seen the below:

  val movementSpec = SpringSpec<IntOffset>(
    dampingRatio = Spring.DampingRatioMediumBouncy,
    stiffness = 200f
  )
  
  var isTransformed by rememberSaveable { mutableStateOf(false) }
  val poster = rememberContentWithOrbitalScope {
    GlideImage(
      modifier = if (isTransformed) {
        Modifier.size(360.dp, 620.dp)
      } else {
        Modifier.size(130.dp, 220.dp)
      }.animateMovement(this, movementSpec),
      imageModel = ItemUtils.urls[3],
      contentScale = ContentScale.Fit
    )
  }

  Orbital(
    modifier = Modifier
      .clickable { isTransformed = !isTransformed }
  ) {
    if (isTransformed) {
      Column(
        Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
      ) {
        poster()
      }
    } else {
      Column(
        Modifier
          .fillMaxSize()
          .padding(20.dp),
        horizontalAlignment = Alignment.End,
        verticalArrangement = Arrangement.Bottom
      ) {
        poster()
      }
    }
  }

Shared Element Transition

<img src="previews/preview3.gif" width="300px" align="center">

The example below shows how to implement shared element transition with the animateSharedElementTransition extension of the OrbitalScope. The rememberContentWithOrbitalScope allows you to create custom animations such as animateSharedElementTransition on the OrbitalScope. You can apply the animateSharedElementTransition animation to specific Composables and customize its AnimationSpec. Also, you can set the different AnimationSpecs for the movement and transformation as seen the below:

@Composable
private fun OrbitalSharedElementTransitionExample() {
  var isTransformed by rememberSaveable { mutableStateOf(false) }
  val item = MockUtils.getMockPosters()[3]
  val poster = rememberContentWithOrbitalScope {
    GlideImage(
      modifier = if (isTransformed) {
        Modifier.fillMaxSize()
      } else {
        Modifier.size(130.dp, 220.dp)
      }.animateSharedElementTransition(
        this,
        SpringSpec(stiffness = 500f),
        SpringSpec(stiffness = 500f)
      ),
      imageModel = item.poster,
      contentScale = ContentScale.Fit
    )
  }

  Orbital(
    modifier = Modifier
      .clickable { isTransformed = !isTransformed }
  ) {
    if (isTransformed) {
      PosterDetails(
        poster = item,
        sharedElementContent = { poster() },
        pressOnBack = {}
      )
    } else {
      Column(
        Modifier
          .fillMaxSize()
          .padding(20.dp),
        horizontalAlignment = Alignment.End,
        verticalArrangement = Arrangement.Bottom
      ) {
        poster()
      }
    }
  }
}

Note: LookaheadLayout is a very experimental API, so measuring complex Composables might throw exceptions.

Shared Element Transition with Multiple Items

The example below shows how to implement shared element transition with multipe items. The basic concept of the usage is the same as the Shared Element Transition example.

<img src="previews/preview0.gif" width="300px" align="center">
  var isTransformed by rememberSaveable { mutableStateOf(false) }
  val items = rememberContentWithOrbitalScope {
    ItemUtils.urls.forEach { url ->
      GlideImage(
        modifier = if (isTransformed) {
          Modifier.size(140.dp, 180.dp)
        } else {
          Modifier.size(100.dp, 220.dp)
        }
          .animateSharedElementTransition(movementSpec, transformationSpec)
          .padding(8.dp),
        imageModel = url,
        contentScale = ContentScale.Fit
      )
    }
  }

  Orbital(
    modifier = Modifier
      .fillMaxSize()
      .clickable { isTransformed = !isTransformed },
    isTransformed = isTransformed,
    onStartContent = {
      Column(
        Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
      ) {
        items()
      }
    },
    onTransformedContent = {
      Row(
        verticalAlignment = Alignment.CenterVertically
      ) { items() }
    }
  )

Shared Element Transition With LazyList

<img src="previews/preview4.gif" width="300px" align="center">

The provided code example illustrates the implementation of shared element transformation (container transform) with a lazy list, such as LazyColumn and LazyRow. The OrbitalScope function initiates a scope in which all layout scopes will be measured and pre-calculated for size and position across all child layouts.

@Composable
fun OrbitalLazyColumnSample() {
  val mocks = MockUtils.getMockPosters()

  Orbital {
    LazyColumn {
      items(mocks, key = { it.name }) { poster ->
        var expanded by rememberSaveable { mutableStateOf(false) }
        AnimatedVisibility(
          remember { MutableTransitionState(false) }
            .apply { targetState = true },
          enter = fadeIn(),
        ) {
          Orbital(modifier = Modifier
            .fillMaxWidth()
            .clickable {
              expanded = !expanded
            }
            .background(color = poster.color, shape = RoundedCornerShape(10.dp))) {
            val title = rememberMovableContentOf {
              Column(
                modifier = Modifier
                  .padding(10.dp)
                  .animateBounds(Modifier),
              ) {
               

Related Skills

View on GitHub
GitHub Stars1.2k
CategoryDevelopment
Updated1h ago
Forks39

Languages

Kotlin

Security Score

100/100

Audited on Apr 1, 2026

No findings