Skip to content

Instantly share code, notes, and snippets.

@iamtekeste
Created April 10, 2024 00:30
Show Gist options
  • Select an option

  • Save iamtekeste/9705fc8c030188c7c73872dfdf6ef03c to your computer and use it in GitHub Desktop.

Select an option

Save iamtekeste/9705fc8c030188c7c73872dfdf6ef03c to your computer and use it in GitHub Desktop.

Revisions

  1. iamtekeste renamed this gist Apr 10, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. iamtekeste created this gist Apr 10, 2024.
    377 changes: 377 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,377 @@
    import "./styles.css";
    import { useRive, Layout, Fit, Alignment } from "@rive-app/react-canvas";
    // @refresh reset
    var Endian;
    (function (Endian) {
    Endian["Little"] = "little";
    Endian["Big"] = "big";
    })(Endian || (Endian = {}));

    var BackingType;
    (function (BackingType) {
    BackingType[(BackingType["UintBool"] = 0)] = "UintBool";
    BackingType[(BackingType["String"] = 1)] = "String";
    BackingType[(BackingType["Float"] = 2)] = "Float";
    BackingType[(BackingType["Color"] = 3)] = "Color";
    })(BackingType || (BackingType = {}));

    class BinaryWriter {
    variableEncodeList = new Uint8Array(8);
    writeIndex = 0;

    constructor(alignment = 1024, endian = Endian.Little) {
    this.alignment = Math.max(1, alignment);
    this.endian = endian;
    this.buffer = new Uint8Array(this.alignment);
    }

    get size() {
    return this.writeIndex;
    }

    nextAlignment(length) {
    return Math.ceil(length / this.alignment) * this.alignment;
    }

    ensureAvailable(byteLength) {
    if (this.writeIndex + byteLength > this.buffer.length) {
    let newLength = this.buffer.length + this.nextAlignment(byteLength);
    const newBuffer = new Uint8Array(newLength);
    newBuffer.set(this.buffer);
    this.buffer = newBuffer;
    }
    }

    get uint8Buffer() {
    return new Uint8Array(
    this.buffer.buffer,
    this.buffer.byteOffset,
    this.size
    );
    }
    getBuffer() {
    return this.buffer;
    }

    writeFloat32(value) {
    this.ensureAvailable(4);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setFloat32(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 4;
    }

    writeFloat64(value) {
    this.ensureAvailable(8);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setFloat64(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 8;
    }

    writeInt8(value) {
    this.ensureAvailable(1);
    this.buffer[this.writeIndex] = value;
    this.writeIndex += 1;
    }

    writeUint8(value) {
    this.ensureAvailable(1);
    this.buffer[this.writeIndex] = value;
    this.writeIndex += 1;
    }

    writeInt16(value) {
    this.ensureAvailable(2);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setInt16(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 2;
    }

    writeUint16(value) {
    this.ensureAvailable(2);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setUint16(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 2;
    }

    writeInt32(value) {
    this.ensureAvailable(4);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setInt32(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 4;
    }

    writeUint32(value) {
    this.ensureAvailable(4);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setUint32(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 4;
    }

    writeInt64(value) {
    this.ensureAvailable(8);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setBigInt64(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 8;
    }

    writeUint64(value) {
    this.ensureAvailable(8);
    const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
    view.setBigUint64(this.writeIndex, value, this.endian === Endian.Little);
    this.writeIndex += 8;
    }

    write(bytes, length) {
    length = length ? length : bytes.length;
    this.ensureAvailable(length);
    this.buffer.set(bytes, this.writeIndex);
    this.writeIndex += length;
    }

    writeVarUint(value) {
    let size = Math.ceil(value.toString(2).length / 7);
    let index = 0;
    let i = 0;
    while (i < size) {
    let part = value & 0x7f;
    value >>= 7;
    this.variableEncodeList[index++] = part;
    i += 1;
    }
    for (let i = 0; i < index - 1; i++) {
    this.variableEncodeList[i] |= 0x80;
    }
    this.write(this.variableEncodeList.subarray(0, index));
    }

    writeString(value, explicitLength = true) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(value);
    if (explicitLength) {
    this.writeVarUint(bytes.length);
    }
    this.write(bytes);
    }
    }
    function createRiveFile() {
    const writer = new BinaryWriter();
    createHeader(writer);
    createArtboard(writer); // 0
    createShape(writer); // 1
    createRectangle(writer); // 2
    createSolidColor(writer, 5); // 3
    createSolidColor(writer, 6); // 4
    createFill(writer, 1); // 5
    createFill(writer, 0); // 6
    createAnimation(writer); // 7
    createKeyedObject(writer, 2); // 8
    createKeyedProperty(writer, 8);
    createKeyFrameDouble(writer, 20, true);
    createKeyFrameDouble(writer, 320);

    return writer.uint8Buffer;
    }

    function createKeyedObject(writer, parentId) {
    writer.writeVarUint(25);

    writer.writeVarUint(51);
    writer.writeVarUint(parentId);

    writer.writeVarUint(0); //
    }

    function createKeyedProperty(writer, parentId) {
    writer.writeVarUint(26);

    writer.writeVarUint(53);
    writer.writeVarUint(13); // animating the x property
    writer.writeVarUint(0); //
    }

    function createKeyFrameDouble(writer, doubleValue, isFirst = false) {
    // value of the property being animated is represented by its data type
    // in this case since x is a double we create a KeyFrameDouble node
    writer.writeVarUint(30);

    if (isFirst) {
    writer.writeVarUint(67); // frame number
    writer.writeVarUint(0);
    } else {
    writer.writeVarUint(67); // frame number
    writer.writeVarUint(60);
    }

    writer.writeVarUint(68);
    writer.writeVarUint(1); // interpolation type

    writer.writeVarUint(70);
    writer.writeFloat32(doubleValue);

    writer.writeVarUint(0); //
    }

    function createFill(writer, parentId) {
    writer.writeVarUint(20); // fill type key
    writer.writeVarUint(5); // parentId core key
    writer.writeVarUint(parentId); // parent of this fill is the artboard
    writer.writeVarUint(0); // done writing backboard
    }

    function createSolidColor(writer, parentId) {
    writer.writeVarUint(18); // SolidColor type key
    writer.writeVarUint(5); // parentId core key
    writer.writeVarUint(parentId); // parent of this SolidColor is the fill
    writer.writeVarUint(37); // colorValue core key
    if (parentId === 5) writer.writeUint32(0xffffffff);
    else writer.writeUint32(0xff313131);
    writer.writeVarUint(0); // done writing backboard
    }

    function generateBitArray(backingFieldTypes, writer) {
    const numProperties = backingFieldTypes.length;
    const numElements = Math.ceil(numProperties / 16); // 16 backing types fit in each Uint32 element
    const bitArray = new Uint32Array(numElements);

    let currentElement = 0;
    let backingTypesEncoded = 0;
    let elementIndex = 0;

    for (let i = 0; i < numProperties; i++) {
    const typeCode = backingFieldTypes[i];

    if (typeCode === undefined) {
    throw new Error(`Invalid backing field type: ${type}`);
    }

    currentElement = (currentElement << 2) | typeCode;
    backingTypesEncoded++;

    if (backingTypesEncoded === 16) {
    writer.writeUint32(currentElement);
    bitArray[elementIndex] = currentElement;
    currentElement = 0;
    backingTypesEncoded = 0;
    elementIndex++;
    }
    }

    if (backingTypesEncoded > 0) {
    currentElement = currentElement << ((16 - backingTypesEncoded) * 2);
    bitArray[elementIndex] = currentElement;
    writer.writeUint32(currentElement);
    }

    return bitArray;
    }
    function createHeader(writer) {
    const fingerprint = new Uint8Array([0x52, 0x49, 0x56, 0x45]);
    writer.write(fingerprint);
    // major v, minor v, fileId
    [7, 0, 731418].forEach((x) => writer.writeVarUint(x));

    writer.writeVarUint(0);
    }

    function createArtboard(writer) {
    writer.writeVarUint(23); // backboard
    writer.writeVarUint(0); // done writing backboard
    writer.writeVarUint(1); // Artboard type key
    writer.writeVarUint(4); // name type key
    writer.writeString("a");

    writer.writeVarUint(7); // Width type key
    writer.writeFloat32(400); // Width

    writer.writeVarUint(8); // height type key
    writer.writeFloat32(100); // height

    writer.writeVarUint(0);
    }

    function createRectangle(writer) {
    writer.writeVarUint(7);
    writer.writeVarUint(5); // parent type key
    writer.writeVarUint(1); //

    writer.writeVarUint(13); // x
    writer.writeFloat32(2333); // x value

    writer.writeVarUint(14); // y
    writer.writeFloat32(25); // y value

    writer.writeVarUint(20); // Width type key
    writer.writeFloat32(50); // Width

    writer.writeVarUint(21); // height type key
    writer.writeFloat32(50); // height

    writer.writeVarUint(31); // border radius
    writer.writeFloat32(50);

    writer.writeVarUint(123); // x origin type key
    writer.writeFloat32(0); // x

    writer.writeVarUint(124); // y origin type key
    writer.writeFloat32(0); // y

    writer.writeVarUint(0);
    }

    function createShape(writer) {
    writer.writeVarUint(3);
    writer.writeVarUint(4);
    writer.writeString("r");
    writer.writeVarUint(5);
    writer.writeVarUint(0);

    writer.writeVarUint(0);
    }

    function createAnimation(writer) {
    writer.writeVarUint(31);

    writer.writeVarUint(55);
    writer.writeString("xzz");

    writer.writeVarUint(59);
    writer.writeVarUint(2);

    writer.writeVarUint(0);
    }

    function downloadRivFile(uint8Array) {
    const blob = new Blob([uint8Array], { type: "application/octet-stream" });
    const url = URL.createObjectURL(blob);

    const a = document.createElement("a");
    a.href = url;
    a.download = `temp.riv`;
    a.click();

    URL.revokeObjectURL(url);
    }
    function HomeAnimation() {
    let fileBytes = createRiveFile();
    // downloadRivFile(fileBytes);

    const { RiveComponent } = useRive({
    buffer: fileBytes,
    artboard: "a",
    autoplay: true,
    });

    return <RiveComponent />;
    }

    export const RiveDemo = () => {
    return <HomeAnimation />;
    };

    export default function App() {
    return (
    <div className="RiveContainer">
    <RiveDemo />
    </div>
    );
    }