diff --git a/README.md b/README.md index e3ce606..d49fe64 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,29 @@ Theatre.js is an animation library for high-fidelity motion graphics. It is desi Theatre can be used both programmatically _and_ visually. -Theatre works with all rendering stacks. You can use it to animate DOM elements, THREE.js objects, or any kind of JavaScript variable. +You can use Theatre.js to: + +* Animate 3D objects made with THREE.js or other 3D libraries + + ![s](https://raw.githubusercontent.com/AriaMinaei/theatre-docs/main/docs/.vuepress/public/preview-3d-short.gif) + +* Animate HTML/SVG via React or other libraries + + ![s](https://raw.githubusercontent.com/AriaMinaei/theatre-docs/main/docs/.vuepress/public/preview-dom.gif) + +* Design micro-interactions + + ![s](https://raw.githubusercontent.com/AriaMinaei/theatre-docs/main/docs/.vuepress/public/preview-micro-interaction.gif) + +* Choreograph generative interactive art + + ![s](https://raw.githubusercontent.com/AriaMinaei/theatre-docs/main/docs/.vuepress/public/preview-generative.gif) + + + +* Or animate any other JS variable + + ![s](https://raw.githubusercontent.com/AriaMinaei/theatre-docs/main/docs/.vuepress/public/preview-console.gif) ## Documentation and Tutorials diff --git a/packages/dataverse/src/index.ts b/packages/dataverse/src/index.ts index f496636..852c4db 100644 --- a/packages/dataverse/src/index.ts +++ b/packages/dataverse/src/index.ts @@ -11,6 +11,6 @@ export {default as iterateAndCountTicks} from './derivations/iterateAndCountTick export {default as iterateOver} from './derivations/iterateOver' export {default as prism} from './derivations/prism/prism' export {default as pointer, getPointerParts, isPointer} from './pointer' -export type {Pointer} from './pointer' +export type {Pointer, PointerType} from './pointer' export {default as Ticker} from './Ticker' export {default as PointerProxy} from './PointerProxy' diff --git a/theatre/core/src/coreExports.ts b/theatre/core/src/coreExports.ts index 429ac90..9b04e1f 100644 --- a/theatre/core/src/coreExports.ts +++ b/theatre/core/src/coreExports.ts @@ -11,6 +11,11 @@ import {InvalidArgumentError} from '@theatre/shared/utils/errors' import {validateName} from '@theatre/shared/utils/sanitizers' import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue' import deepEqual from 'fast-deep-equal' +import type {IDerivation, PointerType} from '@theatre/dataverse' +import {isPointer} from '@theatre/dataverse' +import {isDerivation, valueDerivation} from '@theatre/dataverse' +import type {$IntentionalAny, VoidFn} from '@theatre/shared/utils/types' +import coreTicker from './coreTicker' export {types} /** @@ -32,6 +37,8 @@ export {types} * const config = {state} // here the config contains our saved state * const project = getProject("a-unique-id", config) * ``` + * + * Learn more about exporting https://docs.theatrejs.com/in-depth/#exporting */ export function getProject(id: string, config: IProjectConfig = {}): IProject { const {...restOfConfig} = config @@ -92,7 +99,7 @@ const deepValidateOnDiskState = (projectId: string, s: OnDiskState) => { const validateProjectIdOrThrow = (value: string) => { if (typeof value !== 'string') { throw new InvalidArgumentError( - `Argument 'name' in \`Theatre.getProject(name, ...)\` must be a string. Instead, it was ${userReadableTypeOfValue( + `Argument 'projectId' in \`Theatre.getProject(projectId, ...)\` must be a string. Instead, it was ${userReadableTypeOfValue( value, )}.`, ) @@ -101,13 +108,36 @@ const validateProjectIdOrThrow = (value: string) => { const idTrimmed = value.trim() if (idTrimmed.length !== value.length) { throw new InvalidArgumentError( - `Argument 'name' in \`Theatre.getProject("${value}", ...)\` should not have surrounding whitespace.`, + `Argument 'projectId' in \`Theatre.getProject("${value}", ...)\` should not have surrounding whitespace.`, ) } if (idTrimmed.length < 3) { throw new InvalidArgumentError( - `Argument 'name' in \`Theatre.getProject("${value}", ...)\` should be at least 3 characters long.`, + `Argument 'projectId' in \`Theatre.getProject("${value}", ...)\` should be at least 3 characters long.`, + ) + } +} + +/** + * Calls `callback` every time the pointed value of `pointer` changes. + * + * @param pointer A pointer (like `object.props.x`) + * @param callback The callback is called every time the value of pointerOrDerivation changes + * @returns An unsubscribe function + */ +export function onChange | IDerivation>( + pointer: P, + callback: (value: O) => void, +): VoidFn { + if (isPointer(pointer)) { + const derivation = valueDerivation(pointer) + return derivation.tapImmediate(coreTicker, callback as $IntentionalAny) + } else if (isDerivation(pointer)) { + return pointer.tapImmediate(coreTicker, callback as $IntentionalAny) + } else { + throw new Error( + `Called onChange(p) where p is neither a pointer nor a derivation.`, ) } } diff --git a/theatre/core/src/projects/Project.ts b/theatre/core/src/projects/Project.ts index 76e6533..6c61f4d 100644 --- a/theatre/core/src/projects/Project.ts +++ b/theatre/core/src/projects/Project.ts @@ -99,7 +99,7 @@ export default class Project { `while you are using @theatre/core along with @theatre/sutdio. But since @theatre/studio ` + `is not loaded, the state of project "${id}" will be empty.\n\n` + `To fix this, you need to add @theatre/studio into the bundle and export ` + - `the projet's state. Learn how to do that at https://docs.theatrejs.com/export.html`, + `the projet's state. Learn how to do that at https://docs.theatrejs.com/in-depth/#exporting`, ) } }, 1000) diff --git a/theatre/core/src/projects/TheatreProject.ts b/theatre/core/src/projects/TheatreProject.ts index 1828ba2..e3bbd44 100644 --- a/theatre/core/src/projects/TheatreProject.ts +++ b/theatre/core/src/projects/TheatreProject.ts @@ -11,7 +11,7 @@ import type {$IntentionalAny} from '@theatre/shared/utils/types' */ export type IProjectConfig = { /** - * The state of the project, as [exported](https://docs.theatrejs.com/export.html) by the studio. + * The state of the project, as [exported](https://docs.theatrejs.com/in-depth/#exporting) by the studio. */ state?: $IntentionalAny } diff --git a/theatre/studio/src/panels/DetailPanel/ProjectDetails/ProjectDetails.tsx b/theatre/studio/src/panels/DetailPanel/ProjectDetails/ProjectDetails.tsx index 6d3bb19..fcf3415 100644 --- a/theatre/studio/src/panels/DetailPanel/ProjectDetails/ProjectDetails.tsx +++ b/theatre/studio/src/panels/DetailPanel/ProjectDetails/ProjectDetails.tsx @@ -65,7 +65,10 @@ const ProjectDetails: React.FC<{ This will create a JSON file with the state of your project. You can commit this file to your git repo and include it in your production bundle. - + Here is a quick guide on how to export to production. diff --git a/theatre/studio/src/panels/DetailPanel/ProjectDetails/StateConflictRow.tsx b/theatre/studio/src/panels/DetailPanel/ProjectDetails/StateConflictRow.tsx index 14eb8af..46dca87 100644 --- a/theatre/studio/src/panels/DetailPanel/ProjectDetails/StateConflictRow.tsx +++ b/theatre/studio/src/panels/DetailPanel/ProjectDetails/StateConflictRow.tsx @@ -106,7 +106,7 @@ const InConflict: React.FC<{ Browser state is not based on disk state.{' '} Learn more.