Alejandro Toledo 4 anni fa
parent
commit
d1fa0c96e1

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/addAnimation.tsx

@@ -20,6 +20,9 @@ interface IAddAnimationProps {
     selectedToUpdate?: Animation | undefined;
 }
 
+/**
+ * Controls the creation of a new animation
+ */
 export class AddAnimation extends React.Component<
     IAddAnimationProps,
     {

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/anchorSvgPoint.tsx

@@ -12,6 +12,9 @@ interface IAnchorSvgPointProps {
     framesInCanvasView: { from: number; to: number };
 }
 
+/**
+ * Renders the control point to a keyframe.
+ */
 export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps, { visiblePoint: Vector2 }> {
     constructor(props: IAnchorSvgPointProps) {
         super(props);

+ 163 - 40
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -59,6 +59,9 @@ interface ICurveData {
     id: string;
 }
 
+/**
+ * Animation curve Editor Component
+ */
 export class AnimationCurveEditorComponent extends React.Component<
     IAnimationCurveEditorComponentProps,
     {
@@ -100,11 +103,15 @@ export class AnimationCurveEditorComponent extends React.Component<
         framesResized: number;
     }
 > {
+    readonly _entityName: string;
     private _snippetUrl = "https://snippet.babylonjs.com";
+    // Default values
     private _heightScale: number = 100;
     private _scaleFactor: number = 2;
     private _currentScale: number = 10;
-    readonly _entityName: string;
+    private _pixelFrameUnit: number = 10;
+
+    // SVG properties
     private _svgKeyframes: IKeyframeSvgPoint[] = [];
     private _isPlaying: boolean = false;
     private _graphCanvas: React.RefObject<HTMLDivElement>;
@@ -113,10 +120,10 @@ export class AnimationCurveEditorComponent extends React.Component<
     private _resizeId: ReturnType<typeof setTimeout>;
     private _svgCanvas: React.RefObject<SvgDraggableArea>;
     private _isTargetedAnimation: boolean;
-    private _pixelFrameUnit: number;
     private _resizedTimeline: number;
     private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
     private _mainAnimatable: Nullable<Animatable>;
+
     constructor(props: IAnimationCurveEditorComponentProps) {
         super(props);
         this._entityName = (this.props.entity as any).id;
@@ -125,14 +132,15 @@ export class AnimationCurveEditorComponent extends React.Component<
         this._graphCanvas = React.createRef();
         this._svgCanvas = React.createRef();
 
-        // Default values
-        this._pixelFrameUnit = 10;
+        // Initial values
         const _canvasLength = 240;
         const valueInd = [2, 1.8, 1.6, 1.4, 1.2, 1, 0.8, 0.6, 0.4, 0.2, 0];
 
         let initialSelection;
         let initialPathData;
         let initialLerpMode;
+
+        // Control TargetedAnimation
         if (this.props.entity instanceof TargetedAnimation) {
             this._isTargetedAnimation = true;
             initialSelection = this.props.entity.animation;
@@ -216,6 +224,16 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    componentWillUnmount() {
+        this.playPause(0);
+        if (this._onBeforeRenderObserver) {
+            this.props.scene.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
+            this._onBeforeRenderObserver = null;
+        }
+
+        this._editorWindow.removeEventListener("resize", this.onWindowResizeWidth);
+    }
+
     onCurrentFrameChangeChangeScene(value: number) {
         if (!this._mainAnimatable) {
             return;
@@ -245,6 +263,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         this.setState({ scale: scaleX });
     };
 
+    /**
+     * Returns Array with labels and values for Frame axis in Canvas
+     */
     setFrameAxis(currentLength: number) {
         let halfNegative = new Array(currentLength).fill(0).map((s, i) => {
             return { value: -i * 10, label: -i };
@@ -257,6 +278,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return [...halfNegative, ...halfPositive];
     }
 
+    /**
+     * Returns Array with labels, lines and values for Value axis in Canvas
+    */
     setValueLines() {
         const lineV = this._heightScale / 10;
 
@@ -287,38 +311,25 @@ export class AnimationCurveEditorComponent extends React.Component<
         return [...initialValues, ...pannedValues];
     }
 
-    getValueLabel(i: number) {
-        let label = 0;
-        if (i === 0) {
-            label = 2;
-        }
-        if (i === 50) {
-            label = 1;
-        } else {
-            label = (100 - i * 2) * 0.01 + 1;
-        }
-        return label;
-    }
-
-    resetPlayheadOffset() {
-        if (this._graphCanvas && this._graphCanvas.current) {
-            this.setState({
-                playheadOffset:
-                    this._graphCanvas.current.children[0].clientWidth / (this.state.canvasLength * 10 * this.state.scale),
-            });
-        }
-    }
-
+    /**
+     * Creates a string id from animation name and the keyframe index
+    */
     encodeCurveId(animationName: string, keyframeIndex: number) {
         return animationName + "_" + keyframeIndex;
     }
 
+    /**
+     * Returns the animation keyframe index and the animation selected coordinate (x, y, z)
+    */
     decodeCurveId(id: string) {
         const order = parseInt(id.split("_")[3]);
         const coordinate = parseInt(id.split("_")[2]);
         return { order, coordinate };
     }
 
+    /**
+     * Returns the value from a keyframe
+    */
     getKeyframeValueFromAnimation(id: string) {
         const animation = this.state.selected as Animation;
         const { order, coordinate } = this.decodeCurveId(id);
@@ -378,6 +389,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Determine if two control points are collinear (flat tangent)
+    */
     hasCollinearPoints = (kf: IKeyframeSvgPoint | undefined) => {
         const left = kf?.leftControlPoint;
         const right = kf?.rightControlPoint;
@@ -392,6 +406,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Returns the previous and next keyframe from a selected frame.
+    */
     getPreviousAndNextKeyframe = (frame: number) => {
         let prev,
             next = undefined;
@@ -407,6 +424,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return { prev, next };
     };
 
+    /**
+     * Selects a keyframe in animation based on its Id
+    */
     selectKeyframeFromId = (id: string, actionableKeyframe: IActionableKeyFrame) => {
         this.deselectKeyframes();
         const updatedKeyframes = this.state.svgKeyframes?.map((kf) => {
@@ -424,6 +444,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Resets the current selected keyframe as an updatable pairs by Graph Control Bar
+    */
     resetActionableKeyframe = () => {
         this.setState({
             actionableKeyframe: { frame: undefined, value: undefined },
@@ -432,6 +455,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Sets the selected control point.
+    */
     selectedControlPoint = (type: string, id: string) => {
         const controlPoint = this.state.svgKeyframes?.find((x) => x.id === id);
         if (controlPoint) {
@@ -457,6 +483,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         this.setState({ svgKeyframes: updatedKeyframes });
     };
 
+    /**
+     * Sets the selected control point.
+    */
     deselectKeyframes = () => {
         let updatedKeyframes = this.state.svgKeyframes?.map((kf) => {
             kf.isLeftActive = false;
@@ -472,6 +501,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Update the Animation Key values based on its type
+    */
     updateValuePerCoordinate(
         dataType: number,
         value: number | Vector2 | Vector3 | Color3 | Color4 | Size | Quaternion,
@@ -569,6 +601,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return value;
     }
 
+    /**
+     * Animation should always have a keyframe at Frame Zero
+    */
     forceFrameZeroToExist(keys: IAnimationKey[]) {
         const zeroFrame = keys.find((x) => Math.abs(x.frame) === 0);
         if (zeroFrame === undefined) {
@@ -585,6 +620,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Renders SVG points with dragging of the curve
+    */
     renderPoints = (updatedSvgKeyFrame: IKeyframeSvgPoint, id: string) => {
         let animation = this.state.selected as Animation;
 
@@ -658,6 +696,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         this.selectAnimation(animation, coordinate);
     };
 
+    /**
+     * Updates the left control point on render points
+    */
     updateLeftControlPoint(updatedSvgKeyFrame: IKeyframeSvgPoint, key: IAnimationKey, dataType: number, coordinate: number) {
         if (updatedSvgKeyFrame.isLeftActive) {
             if (updatedSvgKeyFrame.leftControlPoint !== null) {
@@ -690,6 +731,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Updates the right control point on render points
+    */
     updateRightControlPoint(updatedSvgKeyFrame: IKeyframeSvgPoint, key: IAnimationKey, dataType: number, coordinate: number) {
         if (updatedSvgKeyFrame.isRightActive) {
             if (updatedSvgKeyFrame.rightControlPoint !== null) {
@@ -721,6 +765,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Get the current Control Point weight (how far the X value is multiplied)
+    */
     getControlPointWeight(updatedSvgKeyFrame: IKeyframeSvgPoint) {
         let distanceWithPreviousKeyframe = this.state.canvasWidthScale / 4;
         if (this.state.svgKeyframes) {
@@ -748,6 +795,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Handles a Frame selection change
+    */
     handleFrameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
         event.preventDefault();
 
@@ -773,6 +823,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Handles how a value change on a selected frame
+    */
     handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
         event.preventDefault();
 
@@ -796,6 +849,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Set the Keyframe from input control in Graph Control Bar
+    */
     setKeyframeValueFromInput = (actionableKeyframe: IActionableKeyFrame) => {
         this.setState(
             {
@@ -805,6 +861,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         );
     };
 
+    /**
+     * Sets the SVG Keyframe value
+    */
     setKeyframeValue = () => {
         if (
             this.state.actionableKeyframe.frame !== "" &&
@@ -846,6 +905,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Set the flat tangent to the current selected control points.
+    */
     setFlatTangent = () => {
         if (this.state.selected !== null) {
             const keyframes = this.state.svgKeyframes?.filter((kf) => kf.selected).map((k) => this.decodeCurveId(k.id));
@@ -878,6 +940,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Sets Broken mode of lines
+    */
     setBrokenMode = () => {
         if (this.state.selected !== null) {
             let animation = this.state.selected;
@@ -887,6 +952,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Sets a control point to be a linear interpolation with its Keyframe
+    */
     setLerpToActiveControlPoint = () => {
         const animation = this.state.selected;
         if (this.state.svgKeyframes && animation) {
@@ -916,6 +984,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Adds a new keyframe to the curve on canvas click
+    */
     addKeyframeClick = () => {
         if (this.state.selected !== null) {
             let currentAnimation = this.state.selected;
@@ -928,7 +999,7 @@ export class AnimationCurveEditorComponent extends React.Component<
 
             if (existValue === undefined) {
                 let y = this.state.actionableKeyframe.value ?? 1;
-                // check if value exists...
+
                 let arrayValue: any = [];
                 let emptyValue = this.returnZero(currentAnimation.dataType);
 
@@ -988,6 +1059,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Remove keyframe on click
+    */
     removeKeyframeClick = () => {
         if (this.state.selected !== null) {
             let currentAnimation = this.state.selected;
@@ -1004,6 +1078,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Remove the selected keyframes
+    */
     removeKeyframes = (points: IKeyframeSvgPoint[]) => {
         if (this.state.selected !== null) {
             let currentAnimation = this.state.selected;
@@ -1029,6 +1106,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Adds a keyframe
+    */
     addKeyFrame(event: React.MouseEvent<SVGSVGElement>) {
         event.preventDefault();
 
@@ -1106,6 +1186,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return flattened;
     }
 
+    /**
+     * Return a Keyframe zero value depending on Type
+    */
     returnZero(dataType: number) {
         switch (dataType) {
             case Animation.ANIMATIONTYPE_FLOAT:
@@ -1127,6 +1210,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Return the keyframe value as an array depending on type
+    */
     getValueAsArray(valueType: number, value: number | Vector2 | Vector3 | Color3 | Color4 | Size | Quaternion) {
         switch (valueType) {
             case Animation.ANIMATIONTYPE_FLOAT:
@@ -1148,6 +1234,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Sets the keyframe value as an array depending on type
+    */
     setValueAsType(valueType: number, arrayValue: number[]) {
         switch (valueType) {
             case Animation.ANIMATIONTYPE_FLOAT:
@@ -1169,6 +1258,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     }
 
+    /**
+     * Returns the SVG Path Data to render the curve
+    */
     getPathData(animation: Animation | null) {
         if (animation === null) {
             return undefined;
@@ -1291,6 +1383,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return updatedKeyframes;
     }
 
+    /**
+     * Calculates the proper linear tangents if there is no tangents defined
+    */
     curvePathWithoutTangents(
         keyframes: IAnimationKey[],
         data: string,
@@ -1303,6 +1398,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return this.curvePathWithTangents(updatedKeyframes, data, middle, type, coordinate, animationName);
     }
 
+    /**
+     * Calculates the curve data and control points for animation
+    */
     curvePathWithTangents(
         keyframes: IAnimationKey[],
         data: string,
@@ -1458,6 +1556,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return cleanedData;
     }
 
+    /**
+     * Calculates a curve path from predefined easing function
+    */
     curvePath(keyframes: IAnimationKey[], data: string, middle: number, easingFunction: EasingFunction) {
         // This will get 1/4 and 3/4 of points in eased curve
         const u = 0.25;
@@ -1517,6 +1618,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         return data;
     }
 
+    /**
+     * Sets the proper SVG Keyframe points
+    */
     setKeyframePoint(controlPoints: Vector2[], index: number, keyframesCount: number) {
         let svgKeyframe;
         if (index === 0) {
@@ -1595,6 +1699,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         this.cleanCanvas();
     };
 
+    /**
+     * Remove all curves from canvas
+    */
     cleanCanvas = () => {
         this.setState({
             selected: null,
@@ -1605,8 +1712,7 @@ export class AnimationCurveEditorComponent extends React.Component<
     };
 
     /**
-     * Core functions
-     * This section handles main Curve Editor Functions.
+     * Selects the animation and renders the curve
      */
     selectAnimation = (animation: Animation, coordinate?: SelectedCoordinate) => {
         this._svgKeyframes = [];
@@ -1652,6 +1758,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         );
     };
 
+    /**
+     * Set the state for the last selected keyframe
+     */
     postSelectionEvents = () => {
         if (this.state.lastKeyframeCreated !== null) {
             this.deselectKeyframes();
@@ -1670,6 +1779,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Set main animatable to play or pause the animation
+     */
     setMainAnimatable() {
         if (this.state.selected !== null) {
             let target = this.props.entity;
@@ -1723,6 +1835,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         this.setState({ fps: fps, isPlaying: false }, () => this.stopAnimation());
     };
 
+    /**
+    * Check if the animation has easing predefined
+    */
     analyzeAnimationForLerp(animation: Animation | null) {
         if (animation !== null) {
             const { easingMode, easingType, usesTangents } = this.getAnimationData(animation);
@@ -1766,6 +1881,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Calculate the value of the selected frame in curve
+     */
     calculateCurrentPointInCurve = (frame: number): number | undefined => {
         if (
             this.state.selectedPathData !== undefined &&
@@ -1796,9 +1914,12 @@ export class AnimationCurveEditorComponent extends React.Component<
         return undefined;
     };
 
+    /**
+     * Center the position the canvas depending on Keyframe value and frame
+     */
     setCanvasPosition = (keyframe: IAnimationKey) => {
         if (this.state.selected) {
-            // change initialframe, last frame
+            // Changes initialframe and last frame
             const currentFramesInCanvas = this.state.framesInCanvasView.to - this.state.framesInCanvasView.from;
 
             const positionX = (keyframe.frame - currentFramesInCanvas / 2) * this._pixelFrameUnit;
@@ -1831,6 +1952,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Change the timeline animation frame limit
+     */
     changeAnimationLimit = (limit: number) => {
         this.stopAnimation();
         const doubleLimit = limit * 2;
@@ -1841,6 +1965,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     };
 
+    /**
+     * Update the frame in the selected Keyframe
+     */
     updateFrameInKeyFrame = (frame: number, index: number) => {
         if (this.state && this.state.selected) {
             let animation = this.state.selected;
@@ -1909,6 +2036,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+    * Set the frame to selected position on canvas
+    */
     moveFrameTo(e: React.MouseEvent<SVGRectElement, MouseEvent>) {
         this.stopAnimation();
         var svg = e.currentTarget as SVGRectElement;
@@ -1947,16 +2077,6 @@ export class AnimationCurveEditorComponent extends React.Component<
         });
     }
 
-    componentWillUnmount() {
-        this.playPause(0);
-        if (this._onBeforeRenderObserver) {
-            this.props.scene.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
-            this._onBeforeRenderObserver = null;
-        }
-
-        this._editorWindow.removeEventListener("resize", this.onWindowResizeWidth);
-    }
-
     isCurrentFrame(frame: number) {
         return this.state.currentFrame === frame;
     }
@@ -2084,6 +2204,9 @@ export class AnimationCurveEditorComponent extends React.Component<
         }
     };
 
+    /**
+     * Handle the frames quantity and scale on Window resize width
+     */
     onWindowResizeWidth = () => {
         let framesResized: number;
         if (this._graphCanvas.current) {

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationListTree.tsx

@@ -45,6 +45,9 @@ interface ItemCoordinate {
     coordinate: SelectedCoordinate;
 }
 
+/**
+ * Renders a list of current animations.
+ */
 export class AnimationListTree extends React.Component<
     IAnimationListTreeProps,
     {

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/controls.tsx

@@ -13,6 +13,9 @@ interface IControlsProps {
     scrollable: React.RefObject<HTMLDivElement>;
 }
 
+/**
+ * The playback controls for the animation editor
+ */
 export class Controls extends React.Component<IControlsProps, { selected: IAnimationKey; playingType: string }> {
     readonly _sizeOfKeyframe: number = 5;
     constructor(props: IControlsProps) {

+ 18 - 7
inspector/src/components/actionTabs/tabs/propertyGrids/animations/editorControls.tsx

@@ -1,5 +1,4 @@
 import * as React from "react";
-
 import { Observable } from "babylonjs/Misc/observable";
 import { PropertyChangedEvent } from "../../../../../components/propertyChangedEvent";
 import { Animation } from "babylonjs/Animations/animation";
@@ -30,6 +29,9 @@ interface IEditorControlsProps {
     fps: number;
 }
 
+/**
+ * Renders the Curve Editor controls to create, save, remove, load and edit animations
+ */
 export class EditorControls extends React.Component<
     IEditorControlsProps,
     {
@@ -66,7 +68,7 @@ export class EditorControls extends React.Component<
         }
     }
 
-    animationAdded = (animation: Animation) => {
+    onAnimationAdded = (animation: Animation) => {
         this.setState({
             animationsCount: this.recountAnimations(),
             isEditTabOpen: true,
@@ -161,7 +163,10 @@ export class EditorControls extends React.Component<
         }
     };
 
-    emptiedList = () => {
+    /**
+     * Cleans the list when has been emptied
+     */
+    onEmptiedList = () => {
         this.setState({
             animationsCount: this.recountAnimations(),
             isEditTabOpen: false,
@@ -169,6 +174,9 @@ export class EditorControls extends React.Component<
         });
     };
 
+    /**
+     * When animations have been reloaded update tabs
+     */
     animationsLoaded = (numberOfAnimations: number) => {
         this.setState({
             animationsCount: numberOfAnimations,
@@ -203,7 +211,10 @@ export class EditorControls extends React.Component<
         this.setState({ snippetId: id });
     };
 
-    closeAddAnimation = () => {
+     /**
+     * Marks animation tab closed and hides the tab
+     */
+    onCloseAddAnimation = () => {
         this.setState({ isAnimationTabOpen: false, isEditTabOpen: true });
     };
 
@@ -258,10 +269,10 @@ export class EditorControls extends React.Component<
                 {this.props.isTargetedAnimation ? null : (
                     <AddAnimation
                         isOpen={this.state.isAnimationTabOpen}
-                        close={this.closeAddAnimation}
+                        close={this.onCloseAddAnimation}
                         entity={this.props.entity as IAnimatable}
                         setNotificationMessage={this.props.setNotificationMessage}
-                        addedNewAnimation={this.animationAdded}
+                        addedNewAnimation={this.onAnimationAdded}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable}
                         fps={this.state.framesPerSecond}
                         selectedToUpdate={this.state.selected}
@@ -299,7 +310,7 @@ export class EditorControls extends React.Component<
                         entity={this.props.entity}
                         selected={this.props.selected}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable}
-                        empty={this.emptiedList}
+                        empty={this.onEmptiedList}
                         selectAnimation={this.props.selectAnimation}
                         editAnimation={this.editAnimation}
                     />

+ 5 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx

@@ -20,6 +20,10 @@ interface IGraphActionsBarProps {
     frameRange: { min: number | undefined; max: number | undefined };
 }
 
+/**
+ * Has the buttons and actions for the Canvas Graph.
+ * Handles input change and actions (flat, broken mode, set linear control points)
+ */
 export class GraphActionsBar extends React.Component<
     IGraphActionsBarProps,
     { frame: string; value: string; min: number | undefined; max: number | undefined }
@@ -157,7 +161,7 @@ export class GraphActionsBar extends React.Component<
                         onClick={this.props.frameSelectedKeyframes}
                     />
                     <IconButtonLineComponent
-                        tooltip={"Flat Tangents"}
+                        tooltip={this.props.brokenMode ? "Flat selected control point" : "Flat control points"}
                         icon="flat-tangent"
                         onClick={this.props.flatTangent}
                     />

+ 4 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/keyframeSvgPoint.tsx

@@ -3,7 +3,6 @@ import { Vector2 } from "babylonjs/Maths/math.vector";
 import { AnchorSvgPoint } from "./anchorSvgPoint";
 
 const keyInactive = require("./assets/keyInactiveIcon.svg") as string;
-//const keyActive = require("./assets/keyActiveIcon.svg") as string; uncomment when setting active multiselect
 const keySelected = require("./assets/keySelectedIcon.svg") as string;
 
 export interface IKeyframeSvgPoint {
@@ -36,6 +35,10 @@ interface IKeyframeSvgPointProps {
     framesInCanvasView: { from: number; to: number };
 }
 
+/**
+ * Renders the Keyframe as an SVG Element for the Canvas component.
+ * Holds the two control points to generate the proper curve.
+ */
 export class KeyframeSvgPoint extends React.Component<IKeyframeSvgPointProps> {
     constructor(props: IKeyframeSvgPointProps) {
         super(props);

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/loadsnippet.tsx

@@ -24,6 +24,9 @@ interface ILoadSnippetProps {
     animationsLoaded: (numberOfAnimations: number) => void;
 }
 
+/**
+ * Loads animation locally or from the Babylon.js Snippet Server
+ */
 export class LoadSnippet extends React.Component<ILoadSnippetProps, { snippetId: string }> {
     private _serverAddress: string;
     constructor(props: ILoadSnippetProps) {

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/notification.tsx

@@ -6,6 +6,9 @@ interface IPlayheadProps {
     close: () => void;
 }
 
+/**
+ * Renders the notification for the user
+ */
 export class Notification extends React.Component<IPlayheadProps> {
     constructor(props: IPlayheadProps) {
         super(props);

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/playhead.tsx

@@ -6,6 +6,9 @@ interface IPlayheadProps {
   onCurrentFrameChange: (frame: number) => void;
 }
 
+/**
+ * Renders the Playhead
+ */
 export class Playhead extends React.Component<IPlayheadProps> {
   private _direction: number;
   private _active: boolean;

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/saveSnippet.tsx

@@ -28,6 +28,9 @@ interface SelectedAnimation {
     selected: boolean;
 }
 
+/**
+ * Saves the animation snippet to the Babylon.js site or downloads the animation file locally
+ */
 export class SaveSnippet extends React.Component<ISaveSnippetProps, { selectedAnimations: SelectedAnimation[] }> {
     constructor(props: ISaveSnippetProps) {
         super(props);

+ 3 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/scale-label.tsx

@@ -6,6 +6,9 @@ interface ISwitchButtonProps {
     action?: (event: CurveScale) => void;
 }
 
+/**
+ * Displays the current scale
+ */
 export class ScaleLabel extends React.Component<ISwitchButtonProps, { current: CurveScale }> {
     constructor(props: ISwitchButtonProps) {
         super(props);

+ 12 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/svgDraggableArea.tsx

@@ -20,6 +20,11 @@ interface ISvgDraggableAreaProps {
     framesResized: number;
 }
 
+/**
+ * The SvgDraggableArea is a wrapper for SVG Canvas the interaction
+ *
+ * Here we control the drag and key behavior for the SVG components. 
+ */
 export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps, { panX: number; panY: number }> {
     private _active: boolean;
     private _isCurrentPointControl: string;
@@ -120,6 +125,7 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps, {
             var coord = this.getMousePosition(e);
 
             if (coord !== undefined) {
+                // Handles the canvas panning
                 if ((e.target as SVGSVGElement).classList.contains("pannable")) {
                     if (this._isControlKeyPress) {
                         if (this._panStart.x !== 0 && this._panStart.y !== 0) {
@@ -131,6 +137,7 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps, {
                         }
                     }
                 }
+                // Handles the playhead dragging
                 if (
                     e.currentTarget.classList.contains("linear") &&
                     this._playheadDrag !== 0 &&
@@ -151,8 +158,8 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps, {
                     const newFrame = Math.round(moving / unit) + initialFrame;
                     this.props.setCurrentFrame(newFrame);
                 } else {
+                    // Handles the control point dragging
                     var newPoints = [...this.props.keyframeSvgPoints];
-
                     let point = newPoints.find((kf) => kf.id === this._currentPointId);
                     if (point) {
                         if (this._isCurrentPointControl === "left") {
@@ -202,6 +209,10 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps, {
         }
     };
 
+    /**
+    * Handles the canvas panning direction and sets the X and Y values to move the
+    * SVG canvas
+    */
     panDirection() {
         let directionX = 1;
         if (this._movedX < this._panStop.x) {

+ 34 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/timeline.tsx

@@ -17,6 +17,12 @@ interface ITimelineProps {
     resizeWindowProportion: number;
 }
 
+/**
+ * The Timeline for the curve editor
+ *
+ * Has a scrollbar that can be resized and move to left and right. 
+ * The timeline does not affect the Canvas but only the frame container.
+ */
 export class Timeline extends React.Component<
     ITimelineProps,
     {
@@ -29,14 +35,17 @@ export class Timeline extends React.Component<
         limitValue: number;
     }
 > {
+    // Div Elements to display the timeline
     private _scrollable: React.RefObject<HTMLDivElement>;
     private _scrollbarHandle: React.RefObject<HTMLDivElement>;
     private _scrollContainer: React.RefObject<HTMLDivElement>;
     private _inputAnimationLimit: React.RefObject<HTMLInputElement>;
+    // Direction of drag and resize of timeline
     private _direction: number;
     private _scrolling: boolean;
     private _shiftX: number;
     private _active: string = "";
+    // Margin of scrollbar and container
     readonly _marginScrollbar: number;
 
     constructor(props: ITimelineProps) {
@@ -51,6 +60,7 @@ export class Timeline extends React.Component<
         this._shiftX = 0;
         this._marginScrollbar = 3;
 
+        // Limit as Int because is related to Frames.
         const limit = Math.round(this.props.animationLimit / 2);
         const scrollWidth = this.calculateScrollWidth(0, limit);
 
@@ -94,7 +104,6 @@ export class Timeline extends React.Component<
 
     isEnterKeyUp(event: KeyboardEvent) {
         event.preventDefault();
-
         if (event.key === "Enter") {
             this.setControlState();
         }
@@ -127,6 +136,10 @@ export class Timeline extends React.Component<
         );
     }
 
+    /**
+    * @param {number} start Frame from which the scrollbar should begin.
+    * @param {number} end Last frame for the timeline.
+    */
     calculateScrollWidth(start: number, end: number) {
         if (this._scrollContainer.current && this.props.animationLimit !== 0) {
             const containerMarginLeftRight = this._marginScrollbar * 2;
@@ -170,6 +183,9 @@ export class Timeline extends React.Component<
         }
     };
 
+    /**
+    * Handles the change of number of frames available in the timeline.
+    */
     handleLimitChange(event: React.ChangeEvent<HTMLInputElement>) {
         event.preventDefault();
         let newLimit = parseInt(event.target.value);
@@ -209,6 +225,9 @@ export class Timeline extends React.Component<
         }
     };
 
+    /**
+    * Check if the frame is being used as a Keyframe by the animation
+    */
     isFrameBeingUsed(frame: number, direction: number) {
         let used = this.props.keyframes?.find((kf) => kf.frame === frame);
         if (used) {
@@ -270,6 +289,11 @@ export class Timeline extends React.Component<
         this._shiftX = 0;
     };
 
+    /**
+    * Sets the start, end and selection length of the scrollbar. This will control the width and
+    * height of the scrollbar as well as the number of frames available
+    * @param {number} pageX Controls the X axis of the scrollbar movement.
+    */
     moveScrollbar(pageX: number) {
         if (this._scrolling && this._scrollbarHandle.current && this._scrollContainer.current) {
             const moved = pageX - this._shiftX;
@@ -296,6 +320,9 @@ export class Timeline extends React.Component<
         }
     }
 
+    /**
+    * Controls the resizing of the scrollbar from the right handle
+    */
     resizeScrollbarRight(clientX: number) {
         if (this._scrollContainer.current && this._scrollbarHandle.current) {
             const moving = clientX - this._scrollContainer.current.getBoundingClientRect().left;
@@ -323,6 +350,9 @@ export class Timeline extends React.Component<
         }
     }
 
+    /**
+    * Controls the resizing of the scrollbar from the left handle
+    */
     resizeScrollbarLeft(clientX: number) {
         if (this._scrollContainer.current && this._scrollbarHandle.current) {
             const moving = clientX - this._scrollContainer.current.getBoundingClientRect().left;
@@ -354,6 +384,9 @@ export class Timeline extends React.Component<
         }
     }
 
+    /**
+    * Returns array with the expected length between two numbers
+    */
     range(start: number, end: number) {
         return Array.from({ length: end - start }, (_, i) => start + i * 1);
     }