Skip to content

Instantly share code, notes, and snippets.

@xaviervia
Last active February 16, 2021 20:12
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save xaviervia/edbea95d321feacaf0b5d8acd40614b2 to your computer and use it in GitHub Desktop.
Save xaviervia/edbea95d321feacaf0b5d8acd40614b2 to your computer and use it in GitHub Desktop.
Sketch 43 files JSON types

Sketch 43 files JSON types

Based on the example file from the announcement blog post http://sketchplugins.com/d/87-new-file-format-in-sketch-43

type UUID = string // with UUID v4 format

type SketchPositionString = string // '{0.5, 0.67135115527602085}'

type SketchNestedPositionString = string // '{{0, 0}, {75.5, 15}}'

type Base64String = string

type FilePathString = string

type SketchImageCollection = {
  _class: 'imageCollection',
  images: Unknown // TODO
}

type SketchColor = {
  _class: 'color',
  alpha: number,
  blue: number,
  green: number,
  red: number
}

type SketchBorder = {
  _class: 'border',
  isEnabled: bool,
  color: SketchColor,
  fillType: number,
  position: number,
  thickness: number
}

type SketchGradientStop = {
  _class: 'gradientStop',
  color: SketchColor,
  position: number
}

type SketchGradient = {
  _class: 'gradient',
  elipseLength: number,
  from: SketchPositionString,
  gradientType: number,
  shouldSmoothenOpacity: bool,
  stops: [SketchGradientStop],
  to: SketchPositionString
}

type SketchGraphicsContextSettings = {
  _class: 'graphicsContextSettings',
  blendMode: number,
  opacity: number
}

type SketchInnerShadow = {
  _class: 'innerShadow',
  isEnabled: bool,
  blurRadius: number,
  color: SketchColor,
  contextSettings: SketchGraphicsContextSettings,
  offsetX: 0,
  offsetY: 1,
  spread: 0
}

type SketchFill = {
  _class: 'fill',
  isEnabled: bool,
  color: SketchColor,
  fillType: number,
  gradient: SketchGradient,
  noiseIndex: number,
  noiseIntensity: number,
  patternFillType: number,
  patternTileScale: number
}

type SketchShadow = {
  _class: 'shadow',
  isEnabled: bool,
  blurRadius: number,
  color: SketchColor,
  contextSettings: SketchGraphicsContextSettings,
  offsetX: number,
  offsetY: number,
  spread: number
}

type SketchBlur = {
  _class: 'blur',
  isEnabled: bool,
  center: SketchPositionString,
  motionAngle: number,
  radius: number,
  type: number
}

type SketchEncodedAttributes = {
  NSKern: number,
  MSAttributedStringFontAttribute: {
    _archive: Base64String,
  },
  NSParagraphStyle: {
    _archive: Base64String
  },
  NSColor: {
    _archive: Base64String
  }
}

type SketchRect = {
  _class: 'rect',
  constrainProportions: bool,
  height: number,
  width: number,
  x: number,
  y: number
}

type SketchTextStyle = {
  _class: 'textStyle',
  encodedAttributes: SketchEncodedAttributes
}

type SketchBorderOptions = {
  _class: 'borderOptions',
  do_objectID: UUID,
  isEnabled: bool,
  dashPattern: [], // TODO,
  lineCapStyle: number,
  lineJoinStyle: number
}

type SketchColorControls = {
  _class: 'colorControls',
  isEnabled: bool,
  brightness: number,
  contrast: number,
  hue: number,
  saturation: number
}

type SketchStyle = {
  _class: 'style',
  blur: ?[SketchBlur],
  borders: ?[SketchBorder],
  borderOptions: ?SketchBorderOptions,
  contextSettings: ?SketchGraphicsContextSettings,
  colorControls: ?SketchColorControls,
  endDecorationType: number,
  fills: [SketchFill],
  innerShadows: [SketchInnerShadow],
  miterLimit: number,
  shadows: ?[SketchShadow],
  sharedObjectID: UUID,
  startDecorationType: number,
  textStyle: ?SketchTextStyle
}

type SketchSharedStyle = {
  _class: 'sharedStyle',
  do_objectID: UUID,
  name: string,
  value: SketchStyle
}

type SketchExportFormat = {
  _class: 'exportFormat',
  absoluteSize: number,
  fileFormat: string,
  name: string,
  namingScheme: number,
  scale: number,
  visibleScaleType: number
}

type SketchExportOptions = {
  _class: 'exportOptions',
  exportFormats: [SketchExportFormat],
  includedLayerIds: [], // TODO
  layerOptions: number,
  shouldTrim: bool
}

type SketchSharedStyleContainer = {
  _class: 'sharedStyleContainer',
  objects: [SketchSharedStyle]
}

type SketchSymbolContainer = {
  _class: 'symbolContainer',
  objects: [] // TODO
}

type SketchSharedTextStyleContainer {
  _class: 'sharedTextStyleContainer',
  objects: [SketchSharedStyle]
}

type SketchAssetsCollection = {
  _class: 'assetCollection',
  colors: [], // TODO
  gradients: [], // TODO
  imageCollection: SketchImageCollection,
  images: [] // TODO
}

type SketchMSJSONFileReference = {
  _class: 'MSJSONFileReference',
  _ref_class: 'MSImmutablePage' | 'MSImageData',
  _red: FilePathString
}

type SketchMSAttributedString = {
  _class: 'MSAttributedString',
  archivedAttributedString: {
    _archive: Base64String
  }
}

type SketchCurvePoint = {
  _class: 'curvePoint',
  do_objectID: UUID,
  cornerRadius: number,
  curveFrom: SketchPositionString,
  curveMode: number,
  curveTo: SketchPositionString,
  hasCurveFrom: bool,
  hasCurveTo: bool,
  point: SketchPositionString
}

type SketchRulerData = {
  _class: 'rulerData',
  base: number,
  guides: [] // TODO
}

type SketchText = {
  _class: 'text',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedVertical: bool,
  isFlippedHorizontal: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  originalObjectID: UUID,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  attributedString: SketchMSAttributedString,
  automaticallyDrawOnUnderlyingPath: bool,
  dontSynchroniseWithSymbol: bool,
  glyphBounds: SketchNestedPositionString,
  heightIsClipped: bool,
  lineSpacingBehaviour: number,
  textBehaviour: number
}

type SketchShapeGroup = {
  _class: 'shapeGroup',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedVertical: bool,
  isFlippedHorizontal: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  originalObjectID: UUID,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  hasClickThrough: bool,
  layers: [SketchLayer],
  clippingMaskMode: number,
  hasClippingMask: bool,
  windingRule: number
}

type SketchPath = {
  _class: 'path',
  isClosed: bool,
  points: [SketchCurvePoint]
}

type SketchShapePath = {
  _class: 'shapePath',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedVertical: bool,
  isFlippedHorizontal: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  booleanOperation: number,
  edited: bool,
  path: SketchPath
}

type SketchArtboard = {
  _class: 'artboard',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  hasClickThrough: bool,
  layers: [SketchLayer],
  backgroundColor: SketchColor,
  hasBackgroundColor: bool,
  horizontalRulerData: SketchRulerData,
  includeBackgroundColorInExport: bool,
  includeInCloudUpload: bool,
  verticalRulerData: SketchRulerData
}

type SketchBitmap = {
  _class: 'bitmap',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  clippingMask: SketchNestedPositionString,
  fillReplacesImage: bool,
  image: SketchMSJSONFileReference,
  nineSliceCenterRect: SketchNestedPositionString,
  nineSliceScale: SketchPositionString
}

type SketchSymbolInstance = {
  _class: 'symbolInstance',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  horizontalSpacing: number,
  masterInfluenceEdgeMaxXPadding: number,
  masterInfluenceEdgeMaxYPadding: number,
  masterInfluenceEdgeMinXPadding: number,
  masterInfluenceEdgeMinYPadding: number,
  symbolID: number,
  verticalSpacing: number,
  overrides: {
    "0": {} // TODO
  }
}

type SketchGroup = {
  _class: 'group',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  originalObjectID: UUID,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  hasClickThrough: bool,
  layers: [SketchLayer]
}

type SketchRectangle = {
  _class: 'rectangle',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  booleanOperation: number,
  edited: bool,
  path: SketchPath,
  fixedRadius: number,
  hasConvertedToNewRoundCorners: bool
}

type SketchOval = {
  _class: 'oval',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  booleanOperation: number,
  edited: bool,
  path: SketchPath  
}

type SketchLayer =
  | SketchText
  | SketchShapeGroup
  | SketchShapePath
  | SketchBitmap
  | SketchArtboard
  | SketchSymbolInstance
  | SketchGroup
  | SketchRectangle
  | SketchOval

type SketchSymbolMaster = {
  backgroundColor: SketchColor,
  _class: 'symbolMaster',
  do_objectID: UUID,
  exportOptions: [SketchExportOptions],
  frame: SketchRect,
  hasBackgroundColor: bool,
  hasClickThrough: bool,
  horizontalRulerData: SketchRulerData,
  includeBackgroundColorInExport: bool,
  includeBackgroundColorInInstance: bool,
  includeInCloudUpload: bool,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  layers: [SketchLayer],
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  symbolID: UUID,
  verticalRulerData: SketchRulerData
}

// document.json
type SketchDocument = {
  _class: 'document',
  do_objectID: UUID,
  assets: SketchAssetsCollection,
  currentPageIndex: number,
  enableLayerInteraction: bool,
  enableSliceInteraction: bool,
  foreignSymbols: [], // TODO
  layerStyles: SketchSharedStyleContainer,
  layerSymbols: SketchSymbolContainer,
  layerTextStyles: SketchSharedTextStyleContainer,
  pages: [SketchMSJSONFileReference]
}

// pages/*.json
type SketchPage = {
  _class: 'page',
  do_objectID: UUID,
  exportOptions: SketchExportOptions,
  frame: SketchRect,
  hasClickThrough: bool,
  horizontalRulerData: SketchRulerData,
  includeInCloudUpload: bool,
  isFlippedHorizontal: bool,
  isFlippedVertical: bool,
  isLocked: bool,
  isVisible: bool,
  layerListExpandedType: number,
  layers: [SketchSymbolMaster],
  name: string,
  nameIsFixed: bool,
  resizingType: number,
  rotation: number,
  shouldBreakMaskChain: bool,
  style: SketchStyle,
  verticalRulerData: SketchRulerData
}

// meta.json
type SketchMeta = {
  commit: string,
  appVersion: string,
  build: number,
  app: string,
  pagesAndArtboards: {
    [key: UUID]: { name: string }
  },
  fonts: [string], // Font names
  version: number,
  saveHistory: [ string ], // 'BETA.38916'
  autosaved: number,
  variant: string // 'BETA'
}

type SketchDocumentId = UUID

type SketchPageId = UUID

// user.json
type SketchUser = {
  [key: SketchPageId]: {
    scrollOrigin: SketchPositionString,
    zoomValue: number
  },
  [key: SketchDocumentId]: {
    pageListHeight: number,
    cloudShare: Unknown // TODO
  }
}

document assetCollection imageCollection sharedStyleContainer sharedStyle style border color fill gradient gradientStop innerShadow graphicsContextSettings shadow blur symbolContainer sharedTextStyleContainer textStyle MSJSONFileReference MSImmutablePage page exportOptions rect symbolMaster text MSAttributedString shapeGroup shapePath path curvePoint rulerData rectangle oval group bitmap MSImageData colorControls artboard exportFormat symbolInstance borderOptions

@darknoon
Copy link

@darknoon
Copy link

I also think SketchMSJSONFileReference might be not fully defined. If you encode JSON directly in sketch, it has this structure:

{
  class: 'MSJSONOriginalDataReference',
  _ref_class: 'MSImageData',
  _ref: string,
  data: {
    _data: string,
  },
  sha1: {
    _data: string,
  },
};

@scrumit
Copy link

scrumit commented Apr 13, 2017

If you use command.setValue_forKey_onLayer_forPluginIdentifier( then the layer can have a nested array with tag userInfo

@gaurav21r
Copy link

@xaviervia

1. We cannot have Artboards inside Artboards so,

type SketchLayer =
  | SketchText
  | SketchShapeGroup
  | SketchShapePath
  | SketchBitmap
  | SketchArtboard
  | SketchSymbolInstance
  | SketchGroup
  | SketchRectangle
  | SketchOval

becomes

type SketchLayer =
  | SketchText
  | SketchShapeGroup
  | SketchShapePath
  | SketchBitmap
  | SketchSymbolInstance
  | SketchGroup
  | SketchRectangle
  | SketchOval

2. There is an error at SketchPage.

It should be

layers: [SketchArtboard | SketchLayer | SketchSymbolMaster]

instead of

layers: [SketchSymbolMaster]

Try creating a sketch file without Symbols. We can either directly have shapes inside pages or we can have Artboards.

@gaurav21r
Copy link

@xaviervia do you think creating a repo would be better? This is quite a popular gist and I'm sure the repo will attract lots of PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment