ctor(sdkCard) {
    // initialize properties that may be required in init
    this._cardStackSprites = [];

    // set content size to match background plus a little padding
    const cardBackgroundContentSize = this.getCardBackgroundContentSize();
    const contentSize = this.getCardContentSize();

    this._containerNode = new cc.Node();
    this._containerNode.setVisible(false);

    this._containerNodeBack = new cc.Node();
    this._containerNodeBack.setAnchorPoint(0.5, 0.5);
    this._containerNodeBack.setVisible(false);
    this._containerNode.addChild(this._containerNodeBack);

    this._containerNodeFront = new cc.Node();
    this._containerNodeFront.setAnchorPoint(0.5, 0.5);
    this._containerNodeFront.setVisible(false);
    this._containerNode.addChild(this._containerNodeFront);

    this._staticContainerNodeFront = new cc.Node();
    this._staticContainerNodeFront.setAnchorPoint(0.5, 0.5);
    this._staticContainerNodeFront.setVisible(true);
    this._containerNodeFront.addChild(this._staticContainerNodeFront, -1.0);

    // keywords node
    this._keywordsNode = new cc.Node();
    this._keywordsNode.setVisible(false);

    // keywords background
    this._keywordsBG = new cc.DrawNode();
    this._keywordsNode.addChild(this._keywordsBG, -1);
    this._containerNodeFront.addChild(this._keywordsNode, -4);

    // keywords container
    this._keywordsContainerNode = new cc.Node();
    this._keywordsNode.addChild(this._keywordsContainerNode);

    // modifier bar node
    this._modifiersNode = new cc.Node();
    this._modifiersNode.setVisible(false);
    this._modifiersNode.setAnchorPoint(0.5, 0);

    // modifier bar background
    this._modifiersBG = new cc.DrawNode();
    this._modifiersNode.addChild(this._modifiersBG, -1);
    this._containerNodeFront.addChild(this._modifiersNode, -4);

    // modifiers container
    this._modifiersContainerNode = new cc.Node();
    this._modifiersNode.addChild(this._modifiersContainerNode);

    // render pass
    this._renderPass = RenderPass.create(cc.Texture2D.PIXEL_FORMAT_RGBA8888, contentSize.width, contentSize.height, 1, false);
    this._renderPassStackId = RenderPass.get_new_reset_stack_id();
    this._snapshotSprite = GlowSprite.create(this._renderPass.getTexture());
    this._snapshotSprite.setVisible(false);
    this._snapshotSprite.setAntiAlias(false);
    this._snapshotSprite.setGlowPadding(40.0);
    this._snapshotSprite.setGlowThickness(2.0);
    this._snapshotSprite.setGlowBlurStrength('strong');
    this._snapshotSprite.setGlowVerticalFadeFromTop(0.7);
    this._snapshotSprite.setDissolveFrequency(15.0);

    // snapshot uses renderpass texture directly, which may be scaled up to match device pixel ratio
    this._snapshotSprite.setTextureRect(cc.rect(0, 0, contentSize.width, contentSize.height));

    // fix for HiDPI screens: force quad texture coords to go edge to edge and flip for cocos
    this._snapshotSprite._renderCmd.setTextureCoordsEdgeToEdgeAndFlipped();

    // card specific highlight tweaks
    this._snapshotSprite.highlightColor = cc.color(70.0, 200.0, 255.0, 255.0);
    this._snapshotSprite.highlightFrequency = 0.0; // no pulsating
    this._snapshotSprite.highlightIntensity = 4.0;
    this._snapshotSprite.setHighlightThreshold(0.15);
    this._snapshotSprite.highlightBrightness = 0.9;
    this._snapshotSprite.highlightLevelsInBlack = 10.0;
    this._snapshotSprite.highlightLevelsInWhite = 170.0;
    this._snapshotSprite.highlightLevelsInGamma = 1.1; // 1.1 to reduce brights / increase blacks
    this._snapshotSprite.highlightLevelsOutBlack = 10.0;
    this._snapshotSprite.highlightLevelsOutWhite = 255.0;
    this._snapshotSprite.setHighlightBlurStrength('strong');

    // mana label
    this.manaLabel = new cc.LabelTTF('', RSX.font_bold.name, 24, cc.size(48, 24), cc.TEXT_ALIGNMENT_CENTER);
    this.manaLabel.setFontFillColor({ r: 0, g: 33, b: 159 });
    this.manaLabel.setAnchorPoint(0.51, 0.65);
    this.manaLabel.setVisible(false);
    this._staticContainerNodeFront.addChild(this.manaLabel, 2);

    // card name
    this.cardNameLabel = new cc.LabelTTF('', RSX.font_regular.name, 14, cc.size(0, 0), cc.TEXT_ALIGNMENT_CENTER);
    this.cardNameLabel.setFontFillColor(cc.color.WHITE);
    this._staticContainerNodeFront.addChild(this.cardNameLabel, 2);

    // type
    this.cardTypeLabel = new cc.LabelTTF('', RSX.font_regular.name, 12, cc.size(cardBackgroundContentSize.width, 16), cc.TEXT_ALIGNMENT_CENTER);
    this.cardTypeLabel.setFontFillColor(cc.color(144, 202, 207));
    this._staticContainerNodeFront.addChild(this.cardTypeLabel, 2);

    // faction name
    this.factionNameLabel = new cc.LabelTTF('', RSX.font_bold.name, 14, cc.size(cardBackgroundContentSize.width, 30), cc.TEXT_ALIGNMENT_CENTER);
    this.factionNameLabel.setFontFillColor(cc.color(200, 200, 200, 255));
    this.factionNameLabel.enableStroke(cc.color(0, 0, 0, 255), 2, false);
    this.factionNameLabel.setVisible(false);
    this._staticContainerNodeFront.addChild(this.factionNameLabel, 2);

    // stats
    this.atkLabel = new cc.LabelTTF('', RSX.font_bold.name, 24, cc.size(48, 26), cc.TEXT_ALIGNMENT_CENTER);
    this.atkLabel.setFontFillColor(CONFIG.ATK_COLOR);
    this.atkLabel.setVisible(false);
    this._staticContainerNodeFront.addChild(this.atkLabel, 2);

    this.hpLabel = new cc.LabelTTF('', RSX.font_bold.name, 24, cc.size(48, 26), cc.TEXT_ALIGNMENT_CENTER);
    this.hpLabel.setFontFillColor(CONFIG.HP_COLOR);
    this.hpLabel.setVisible(false);
    this._staticContainerNodeFront.addChild(this.hpLabel, 2);

    // description
    this.cardDescriptionLabel = new BaseLabel('', RSX.font_light.name, 13, cc.size(cardBackgroundContentSize.width - 20, 0), cc.TEXT_ALIGNMENT_CENTER);
    const fontNamesByFormattingTag = {};
    fontNamesByFormattingTag[CONFIG.FORMATTING_ENGINE.boldStart] = RSX.font_bold.name;
    this.cardDescriptionLabel.setFontNamesByFormattingTag(fontNamesByFormattingTag);
    this.cardDescriptionLabel.setFontFillColor(cc.color(144, 202, 207));
    // this.cardDescriptionLabel.setOpacity(200);
    this.cardDescriptionLabel.setLineHeight(16);
    this.cardDescriptionLabel.setAnchorPoint(0.5, 0.5);
    this.cardDescriptionLabel.setPosition(0.0, -90);
    this._staticContainerNodeFront.addChild(this.cardDescriptionLabel, 2);

    this.whenRequiredResourcesReady().then((requestId) => {
      if (!this.getAreResourcesValid(requestId)) return; // load invalidated or resources changed

      // card front background
      this.cardBackgroundSprite = GlowSprite.create(RSX.card_neutral_spell.img);
      this._containerNodeFront.addChild(this.cardBackgroundSprite, -3.0);

      // shadow
      this._unitShadow = BaseSprite.create(RSX.unit_shadow.img);
      this._unitShadow.setOpacity(0.0);
      this._staticContainerNodeFront.addChild(this._unitShadow);

      // mana gem
      this._manaGemSprite = BaseSprite.create(RSX.icon_mana.img);
      this._manaGemSprite.setVisible(false);
      this._staticContainerNodeFront.addChild(this._manaGemSprite);

      // rarity sprites
      this._raritySpriteCommon = new BaseSprite(RSX.card_rarity_common.img);
      this._raritySpriteCommon.setVisible(false);
      this._staticContainerNodeFront.addChild(this._raritySpriteCommon, 2);
      this._raritySpriteRare = new BaseSprite(RSX.card_rarity_rare.img);
      this._raritySpriteRare.setVisible(false);
      this._staticContainerNodeFront.addChild(this._raritySpriteRare, 2);
      this._raritySpriteEpic = new BaseSprite(RSX.card_rarity_epic.img);
      this._raritySpriteEpic.setVisible(false);
      this._staticContainerNodeFront.addChild(this._raritySpriteEpic, 2);
      this._raritySpriteLegendary = new BaseSprite(RSX.card_rarity_legendary.img);
      this._raritySpriteLegendary.setVisible(false);
      this._staticContainerNodeFront.addChild(this._raritySpriteLegendary, 2);
      this._raritySpriteMythron = new BaseSprite(RSX.card_rarity_mythron.img);
      this._raritySpriteMythron.setVisible(false);
      this._staticContainerNodeFront.addChild(this._raritySpriteMythron, 2);

      // glow map
      this._glowMapNode = new FXGlowImageMap({
        spriteIdentifier: RSX.card_shadow_map.img,
        // blendSrc: "SRC_ALPHA",
        // blendDst: "ONE",
        scale: 1.0,
        gamma: 2.0,
        glowColor: CONFIG.DEFAULT_GLOW_COLOR,
      });
      this._glowMapNode.setVisible(false);

      // silenced sprite
      this._silencedSprite = new BaseSprite(RSX.card_silenced.img);
      this._silencedSprite.setAnchorPoint(0.5, 0.5);
      this._silencedSprite.setPosition(0.0, -88);
      this._silencedSprite.setVisible(false);
      this._staticContainerNodeFront.addChild(this._silencedSprite, 9999);

      // outline glows for select reveal
      this._outlineGlowUnit = BaseSprite.create(RSX.card_reveal_glow_unit.img);
      this._outlineGlowUnit.setPosition(0.0, 0.0);
      this._outlineGlowUnit.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowUnit.setVisible(false);
      this._outlineGlowUnitAlt = BaseSprite.create(RSX.card_reveal_glow_unit.img);
      this._outlineGlowUnitAlt.setPosition(0.0, 0.0);
      this._outlineGlowUnitAlt.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowUnitAlt.setVisible(false);
      this._outlineGlowUnitBlurred = BaseSprite.create(RSX.card_reveal_glow_unit_blurred.img);
      this._outlineGlowUnitBlurred.setPosition(0.0, 0.0);
      this._outlineGlowUnitBlurred.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowUnitBlurred.setVisible(false);

      this._outlineGlowSpell = BaseSprite.create(RSX.card_reveal_glow_spell.img);
      this._outlineGlowSpell.setPosition(0.0, 0.0);
      this._outlineGlowSpell.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowSpell.setVisible(false);
      this._outlineGlowSpellAlt = BaseSprite.create(RSX.card_reveal_glow_spell.img);
      this._outlineGlowSpellAlt.setPosition(0.0, 0.0);
      this._outlineGlowSpellAlt.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowSpellAlt.setVisible(false);
      this._outlineGlowSpellBlurred = BaseSprite.create(RSX.card_reveal_glow_spell_blurred.img);
      this._outlineGlowSpellBlurred.setPosition(0.0, 0.0);
      this._outlineGlowSpellBlurred.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowSpellBlurred.setVisible(false);

      this._outlineGlowArtifact = BaseSprite.create(RSX.card_reveal_glow_artifact.img);
      this._outlineGlowArtifact.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowArtifact.setVisible(false);
      this._outlineGlowArtifactAlt = BaseSprite.create(RSX.card_reveal_glow_artifact.img);
      this._outlineGlowArtifactAlt.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowArtifactAlt.setVisible(false);
      this._outlineGlowArtifactBlurred = BaseSprite.create(RSX.card_reveal_glow_artifact_blurred.img);
      this._outlineGlowArtifactBlurred.setBlendFunc(cc.SRC_ALPHA, cc.ONE);
      this._outlineGlowArtifactBlurred.setVisible(false);

      // position elements
      const centerPosition = this.getCenterPosition();

      // container elements in center
      this._glowMapNode.setPosition(centerPosition);

      // outline glow elements in the center since they sit above containers
      this._outlineGlowArtifactBlurred.setPosition(centerPosition);
      this._outlineGlowArtifactAlt.setPosition(centerPosition);
      this._outlineGlowArtifact.setPosition(centerPosition);
      this._outlineGlowUnitBlurred.setPosition(centerPosition);
      this._outlineGlowUnitAlt.setPosition(centerPosition);
      this._outlineGlowUnit.setPosition(centerPosition);
      this._outlineGlowSpellBlurred.setPosition(centerPosition);
      this._outlineGlowSpellAlt.setPosition(centerPosition);
      this._outlineGlowSpell.setPosition(centerPosition);

      // contained elements relative to center
      this._manaGemSprite.setPosition(-100, cardBackgroundContentSize.height * 0.5 - 20);
      this.manaLabel.setPosition(-100, cardBackgroundContentSize.height * 0.5 - 17);
      this.atkLabel.setPosition(-61, -32);
      this.hpLabel.setPosition(59, -32);
      this.cardNameLabel.setPosition(0.0, 21.0);
      this.cardTypeLabel.setPosition(0.0, 4.0);
      this.factionNameLabel.setPosition(0.0, -150.0);
      this._raritySpriteCommon.setPosition(0.0, -25.0);
      this._raritySpriteRare.setPosition(0.0, -25.0);
      this._raritySpriteEpic.setPosition(0.0, -25.0);
      this._raritySpriteLegendary.setPosition(0.0, -25.0);
      this._raritySpriteMythron.setPosition(0.0, -25.0);

      // add children after cocos ctor
      this.addChild(this._glowMapNode, -2);

      // add outline glows
      this.addChild(this._outlineGlowUnit, 3);
      this.addChild(this._outlineGlowUnitAlt, 3);
      this.addChild(this._outlineGlowUnitBlurred, 3);
      this.addChild(this._outlineGlowSpell, 3);
      this.addChild(this._outlineGlowSpellAlt, 3);
      this.addChild(this._outlineGlowSpellBlurred, 3);
      this.addChild(this._outlineGlowArtifact, 3);
      this.addChild(this._outlineGlowArtifactAlt, 3);
      this.addChild(this._outlineGlowArtifactBlurred, 3);

      // TODO: for performance, snapshot the non animated elements
      // this.recordStaticSnapshot();
    });

    // do super ctor
    this._super(sdkCard);

    // set content size immediately
    // otherwise content size will not be set until assets load
    // which could cause values that use content size to be incorrect
    this.setContentSize(contentSize);

    // position elements
    const centerPosition = this.getCenterPosition();

    // container elements in center
    this._snapshotSprite.setPosition(centerPosition);
    this._containerNodeFront.setPosition(centerPosition);
    this._containerNodeBack.setPosition(centerPosition);

    // add children after cocos ctor
    this.addChild(this._snapshotSprite, 2);
    this.addChild(this._containerNode, 1);
  }
*************************************************************************
 CardNode
 var CardNode = SdkNode
 CardNode.create()
 - node used to display cards as they appear in UI card format
**************************************************************************