
Esta é a segunda parte do artigo sobre a criação de uma ferramenta que pode exportar todos os ícones colocados em um arquivo de esboço: em diferentes formatos, para diferentes plataformas, com a possibilidade de testar A / B de cada ícone.
Você pode ler a primeira parte
do link .

Na última vez, preparamos arquivos de esboço contendo todos os ícones nos estilos corretos e com os nomes corretos. É a vez de escrever código.
Basta dizer que passamos por tentativa e erro. Depois que o líder da nossa equipe,
Nihil Verma , que lançou as bases do script, desenvolveu o código-chave, iniciei um processo que exigia pelo menos três fases de refatoração e muitas modificações. Por esse motivo, não abordarei os detalhes da criação do script e me concentrarei em como ele funciona hoje, em sua forma final.
Script de compilação
O script de compilação escrito no Node.js é bastante direto em seu trabalho: importando dependências, declarando uma lista de arquivos do Sketch para processamento (é uma lista de marcas, cada uma com uma lista de arquivos relacionados a ele) e garantindo que o Sketch esteja instalado no cliente , o script processa as marcas, por sua vez, realizando uma série de ações com cada uma delas.
- Leva tokens de design apropriados para as marcas (precisamos de valores de cores).
- Clona arquivos de esboço associados à marca, descompacta-os para extrair arquivos JSON internos e processa alguns de seus valores internos (mais sobre isso posteriormente).
- Lê os metadados necessários desses arquivos JSON ( document.json , meta.json e pages / pageUniqueID.json ). Estamos interessados em listas de estilos e recursos / ícones comuns contidos nos arquivos.
- Após mais algumas manipulações com arquivos JSON, ele recria o arquivo morto e, usando arquivos de Sketch (clonados e atualizados), exporta e cria os arquivos finais de saída para três plataformas (iOS, Android, Mobile Web).
As partes relevantes do script de construção podem ser encontradas aqui:
// ... modules imports here const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], }; const SKETCH_FOLDER_PATH = path.resolve(__dirname, '../src/'); const SKETCH_TEMP_PATH = path.resolve(SKETCH_FOLDER_PATH, 'tmp'); const DESTINATION_PATH = path.resolve(__dirname, '../dist'); console.log('Build started...'); if (sketchtool.check()) { console.log(`Processing Sketch file via ${sketchtool.version()}`); build(); } else { console.info('You need Sketch installed to run this script'); process.exit(1); } // ---------------------------------------- function build() { // be sure to start with a blank slate del.sync([SKETCH_TEMP_PATH, DESTINATION_PATH]); // process all the brands declared in the list of Sketch files Object.keys(SKETCH_FILES).forEach(async (brand) => { // get the design tokens for the brand const brandTokens = getDesignTokens(brand); // prepare the Sketch files (unzipped) and get a list of them const sketchUnzipFolders = await prepareSketchFiles({ brand, sketchFileNames: SKETCH_FILES[brand], sketchFolder: SKETCH_FOLDER_PATH, sketchTempFolder: SKETCH_TEMP_PATH }); // get the Sketch metadata const sketchMetadata = getSketchMetadata(sketchUnzipFolders); const sketchDataSharedStyles = sketchMetadata.sharedStyles; const sketchDataAssets = sketchMetadata.assetsMetadata; generateAssetsPDF({ platform: 'ios', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); generateAssetsSVGDynamicMobileWeb({ platform: 'mw', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); generateAssetsVectorDrawableDynamicAndroid({ platform: 'android', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); }); }
De fato, o código do pipeline é muito mais complicado. O motivo dessa complexidade está nas
prepareSketchFiles
,
getSketchMetadata
e
generateAssets[format][platform]
. Abaixo tentarei descrevê-los com mais detalhes.
Preparando arquivos de esboço
A primeira etapa do processo de montagem é a preparação dos arquivos do Sketch, que posteriormente serão usados para exportar recursos para várias plataformas.
Os arquivos associados a uma marca específica (por exemplo, no caso do Blendr, são
arquivos icons_common.sketch e
icons_blendr.sketch ) são clonados em uma pasta temporária (mais precisamente, em uma subpasta nomeada após o processamento da marca) e descompactados.
Em seguida, os arquivos JSON são processados. Um prefixo é adicionado ao nome dos recursos sujeitos ao teste A / B - assim, durante a exportação, eles são salvos em uma subpasta com um nome predefinido (correspondente ao nome exclusivo do experimento). Você pode entender se um recurso está sujeito ao teste A / B pelo nome da página em que está armazenado: se estiver, o nome conterá o prefixo "
XP_ ".

No exemplo acima, os recursos exportados serão armazenados em uma subpasta "
this__is_an_experiment " com um nome de arquivo no formato "
icon-name [variant-name] .ext ".
Leitura de metadados de esboço
A segunda etapa importante é extrair todos os metadados necessários dos arquivos do Sketch, ou melhor, dos arquivos JSON internos. Como vimos acima, esses são dois arquivos principais (
document.json e
meta.json ) e arquivos de página (
pages / pageUniqueId.json ).
O arquivo
document.json é usado para obter a lista de estilos comuns que aparecem sob a propriedade do objeto
layerStyles :
{ "_class": "document", "do_objectID": "45D2DA82-B3F4-49D1-A886-9530678D71DC", "colorSpace": 1, ... "layerStyles": { "_class": "sharedStyleContainer", "objects": [ { "_class": "sharedStyle", "do_objectID": "9BC39AAD-CDE6-4698-8EA5-689C3C942DB4", "name": "features/feature-like", "value": { "_class": "style", "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.10588235408067703, "green": 0.4000000059604645, "red": 1 }, "fillType": 0, "noiseIndex": 0, "noiseIntensity": 0, "patternFillType": 1, "patternTileScale": 1 } ], "blur": {...}, "startMarkerType": 0, "endMarkerType": 0, "miterLimit": 10, "windingRule": 1 } }, ...
Armazenamos informações básicas sobre cada estilo em um objeto de formato de valor-chave. Ele será usado posteriormente quando precisarmos extrair o nome do estilo com base em um ID exclusivo (propriedade
do_objectID
no Sketch):
const parsedSharedStyles = {}; parsedDocument.layerStyles.objects.forEach((object) => { parsedSharedStyles[object.do_objectID] = { name: object.name, isFill: _.get(object, 'value.fills[0].color') !== undefined, isBorder: _.get(object, 'value.borders[0].color') !== undefined, }; });
Agora vamos ao arquivo
meta.json e obtemos uma lista de páginas. Estamos interessados em seu
unique-id
e
name
unique-id
:
{ "commit": "623a23f2c4848acdbb1a38c2689e571eb73eb823", "pagesAndArtboards": { "EE6BE8D9-9FAD-4976-B0D8-AB33D2B5DBB7": { "name": "Icons", "artboards": { "3275987C-CE1B-4369-B789-06366EDA4C98": { "name": "badge-feature-like" }, "C6992142-8439-45E7-A346-FC35FA01440F": { "name": "badge-feature-crush" }, ... "7F58A1C4-D624-40E3-A8C6-6AF15FD0C32D": { "name": "tabbar-livestream" } ... } }, "ACF82F4E-4B92-4BE1-A31C-DDEB2E54D761": { "name": "XP_this__is_an_experiment", "artboards": { "31A812E8-D960-499F-A10F-C2006DDAEB65": { "name": "this__is_an_experiment/tabbar-livestream[variant1]" }, "20F03053-ED77-486B-9770-32E6BA73A0B8": { "name": "this__is_an_experiment/tabbar-livestream[variant2]" }, "801E65A4-3CC6-411B-B097-B1DBD33EC6CC": { "name": "this__is_an_experiment/tabbar-livestream[control]" } } },
Em seguida, lemos os arquivos JSON correspondentes a cada página na pasta
pages (repito que os nomes dos arquivos têm o formato
[pageUniqueId] .json ) e estudamos os recursos armazenados nesta página (eles se parecem com camadas). Assim, obtemos o
nome , a
largura / altura de cada ícone, os
metadados do Sketch para o ícone dessa camada e, se estamos lidando com uma página de
experiência , o nome do
teste A / B e uma
variante desse ícone.
Nota : o objeto page.json possui um dispositivo muito complexo, por isso não vou insistir nele. Se você estiver interessado no que está dentro, aconselho a criar um novo arquivo de esboço vazio, adicionar algum conteúdo a ele e salvá-lo; renomeie sua extensão para ZIP, descompacte-o e examine um dos arquivos na pasta páginas.
No processo de processamento de pranchetas, também criaremos uma
lista de experimentos (e recursos relacionados). Precisamos dele para determinar quais variações do ícone são usadas em qual experimento - os nomes das variações do ícone estão anexados ao objeto "base".
Para cada arquivo de esboço
assetsMetadata
marca que está sendo processado, criamos um objeto
assetsMetadata
seguinte aparência:
{ "navigation-bar-edit": { "do_objectID": "86321895-37CE-4B3B-9AA6-6838BEDB0977", ...sketch_artboard_properties, "name": "navigation-bar-edit", "assetname": "navigation-bar-edit", "source": "icons_common", "width": 48, "height": 48 "layers": [ { "do_objectID": "A15FA03C-DEA6-4732-9F85-CA0412A57DF4", "name": "Path", ...sketch_layer_properties, "sharedStyleID": "6A3C0FEE-C8A3-4629-AC48-4FC6005796F5", "style": { ... "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.8784313725490196, "green": 0.8784313725490196, "red": 0.8784313725490196 }, } ], "miterLimit": 10, "startMarkerType": 0, "windingRule": 1 }, }, ], ... }, "experiment-name/navigation-bar-edit[variant]": { "do_objectID": "00C0A829-D8ED-4E62-8346-E7EFBC04A7C7", ...sketch_artboard_properties, "name": "experiment-name/navigation-bar-edit[variant]", "assetname": "navigation-bar-edit", "source": "icons_common", "width": 48, "height": 48 ...
Como você pode ver, no experimento, um único ícone (neste caso
, barra de navegação de edição ) pode corresponder a muitos recursos. Ao mesmo tempo, o mesmo ícone pode aparecer com o mesmo nome em outro arquivo de esboço associado à marca.
Isso é muito útil : usamos esse truque para compilar um conjunto comum de ícones e depois identificar opções específicas de acordo com a marca. Por isso, declaramos os arquivos de esboço associados a uma determinada marca como uma matriz:
const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], };
Nesse caso, a ordem é de importância fundamental. De fato, na função
getSketchMetadata
chamada pelo script, não retornamos objetos
assetsMetadata
um de cada vez como um arquivo de lista. Em vez disso, realizamos uma mesclagem profunda de objetos - os combinamos e retornamos um único objeto
assetsMetadata
.
Em geral, isso nada mais é do que uma fusão "lógica" de arquivos do Sketch e seus recursos em um único arquivo. No entanto, a lógica não é tão simples quanto parece. Aqui está um diagrama que criamos na tentativa de descobrir o que acontece quando ícones com o mesmo nome (e possivelmente sujeitos ao teste A / B) em arquivos diferentes são associados à mesma marca:

Criação de arquivos prontos em diferentes formatos para diferentes plataformas
A etapa final do nosso processo é a criação direta de arquivos de ícones em diferentes formatos para diferentes plataformas (PDF para iOS, SVG / JSX para Web e VectorDrawable para Android).
Como você pode ver no número de parâmetros passados para as funções
generateAssets[format][platform]
, essa parte do pipeline é a mais complexa. É aqui que o processo começa a ser interrompido e alterado, dependendo da plataforma. Abaixo, você verá o curso lógico do script como um todo e como a parte relacionada à geração de recursos é dividida em três processos semelhantes, mas diferentes:

Para criar recursos prontos com as cores corretas correspondentes à marca que está sendo processada, precisaremos realizar mais algumas manipulações com arquivos JSON. Analisamos todas as camadas às quais o estilo geral é aplicado e substituímos os valores das cores pelas cores do token de design da marca.
Para gerar arquivos para o Android, você precisa executar uma ação adicional (sobre isso um pouco mais tarde):
windingRule
propriedade
fill-rule
de cada camada de
even-odd
para
non-zero
(isso é controlado pela propriedade
windingRule
do objeto JSON, na qual 1 significa "ímpar / par" e 0 é "diferente de zero").
Depois de fazer essas manipulações, empacotamos os arquivos JSON de volta em um arquivo de esboço padrão para processar e exportar recursos com propriedades atualizadas (arquivos clonados e atualizados são arquivos de esboço comuns, podem ser abertos, visualizados, editados, salvos etc.) )
Depois disso, usamos o SketchTool (agrupado
em Node ) para exportar automaticamente todos os recursos em formatos adequados para plataformas. Para cada um dos arquivos associados à marca (ou melhor, suas versões clonadas e atualizadas), executamos o seguinte comando:
sketchtool.run(`export slices ${cloneSketchFile} --formats=svg --scales=1 --output=${destinationFolder} --overwriting`);
Como você pode imaginar, esse comando exporta recursos para a pasta de destino em um formato específico, opcionalmente usando a escala (mantemos a escala original por enquanto). A chave aqui é a opção
-overwriting
: assim como fazemos uma mesclagem profunda de objetos
assetsMetadata
(correspondentes aos arquivos de esboço "lógicos"), ao exportar, mesclamos muitos arquivos em um diretório (relacionado à marca / plataforma). Isso significa que se o recurso - identificado pelo nome da camada - já existir no arquivo de esboço anterior, ele será substituído durante a próxima exportação. Novamente, isso nada mais é do que uma operação de mesclagem normal.
No entanto, neste exemplo, alguns recursos podem vir a ser "fantasmas". Isso acontece quando o ícone no arquivo é submetido ao teste A / B, mas é substituído no arquivo subseqüente. Em seguida, os arquivos variantes são exportados para a pasta de destino, possuem um link correspondente ao recurso no objeto
assetsMetadata
(com sua chave e propriedades), mas não são associados a nenhum recurso base (devido à fusão profunda dos objetos
assetsMetadata
). Esses arquivos serão excluídos mais tarde, antes de concluir o processo.
Como já mencionado, plataformas diferentes requerem formatos de saída diferentes. Os arquivos iOS cabem em PDFs, e podemos exportá-los diretamente usando o comando SketchTool. Os arquivos JSX são necessários para a Web móvel e o VectorDrawable para Android. Por esse motivo, exportamos recursos no formato SVG para uma pasta temporária e depois os processamos.
PDFs para iOS
Curiosamente, o PDF é o único (?) Formato que o Xcode e o OS / iOS suportam para importar e renderizar recursos vetoriais (
aqui está uma breve explicação da escolha
da Apple).
Como podemos exportar diretamente para PDF via SketchTool, não são necessárias etapas adicionais: basta salvar os arquivos diretamente na pasta de destino e pronto.
Arquivos da Web React / JSX
No caso da Web, usamos o Nó da biblioteca SVGR, que permite converter componentes SVG em React. No entanto, queremos fazer algo abruptamente: "dinamicamente colorir" o ícone em tempo de execução (as cores são retiradas dos tokens). Para fazer isso, antes da conversão, alteramos os valores de
fill
dos vetores aos quais o estilo geral foi aplicado anteriormente aos valores dos tokens correspondentes a esse estilo.
Portanto, se o arquivo
badge-feature-like.svg exportado do Sketch se parecer com o seguinte:
<?xml version="1.0" encoding="UTF-8"?> <svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>" xmlns:xlink="<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>"> <!-- Generator: sketchtool 52.2 (67145) -<a href="http://www.bohemiancoding.com/sketch"> http://www.bohemiancoding.com/sketch</a> --> <title>badge-feature-like</title> <desc>Created with sketchtool.</desc> <g id="Icons" fill="none" fill-rule="evenodd"> <g id="badge-feature-like"> <circle id="circle" fill="#E71032" cx="64" cy="64" r="64"> <path id="Shape" fill="#FFFFFF" d="M80.4061668,..."></path> </g> </g> </svg>
o
ícone final resource /
badge-feature-like.js ficará assim:
/* This file is generated automatically - DO NOT EDIT */ /* eslint-disable max-lines,max-len,camelcase */ const React = require('react'); module.exports = function badge_feature_like({ tokens }) { return ( <svg data-origin="pipeline" viewBox="0 0 128 128"> <g fill="none" fillRule="evenodd"> <circle fill={tokens.TOKEN_COLOR_FEATURE_LIKED_YOU} cx={64} cy={64} r={64} /> <path fill="#FFF" d="M80.4061668,..." /> </g> </svg> ); };
Como você pode ver, substituímos a cor de
fill
estático por uma dinâmica que aceita valores de tokens (eles podem ser disponibilizados para o componente React
<Icon/>
por meio da API de contexto, mas essa é uma história diferente).
Essa substituição é possível graças aos metadados do Sketch para os ativos do objeto
assetsMetadata
: percorrendo recursivamente as camadas, você pode criar um seletor DOM (no exemplo acima,
#Icons
#badge-feature-like #circle
) e usá-lo para procurar um nó na árvore SVG e substituir seu valor atributo de
fill
(para isso precisamos da biblioteca
cheerio ).
Arquivos desenháveis para Android
O Android suporta gráficos vetoriais usando o formato vetorial
VectorDrawable personalizado. Normalmente, a conversão de SVG para VectorDrawable é feita
diretamente no Android Studio . No entanto, queríamos automatizar completamente o processo, então estávamos procurando uma maneira de converter usando o código.
Depois de estudar várias ferramentas e bibliotecas, decidimos pelo
svg2vectordrawable . Ele não é apenas suportado ativamente (em qualquer caso, mais ativo que todos os outros), mas também mais funcional que o resto.
As realidades são que VectorDrawable e SVG não são iguais em sua funcionalidade: algumas funções SVG (por exemplo, gradientes radiais e realce complexo) não são suportadas pelo VectorDrawable, enquanto outras começaram a ser suportadas recentemente (a partir da API Android 24). Um dos problemas decorrentes disso é que as versões mais antigas (até 24)
não suportam o valor par-ímpar do atributo de regra de preenchimento . No entanto, no Badoo precisamos de suporte para o Android 5 e superior. Por isso, em um dos estágios anteriores, aumentamos o
fill
cada vetor nos arquivos de esboço para um valor
non-zero
.
Em princípio, os designers podem executar esta ação manualmente:

Mas é fácil esquecer e cometer um erro. Portanto, decidimos adicionar uma etapa adicional ao processo para Android, na qual todos os vetores no JSON são convertidos automaticamente para
non-zero
. Isso é feito para que, ao exportar ícones para o SVG, eles já estejam no formato necessário e cada objeto VectorDrawable criado seja suportado por dispositivos no Android 5.
O arquivo
badge-feature-like.xml concluído é assim:
<!-- This file is generated automatically - DO NOT EDIT --> <vector xmlns:android="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>" android:width="128dp" android:height="128dp" android:viewportWidth="128" android:viewportHeight="128"> <path android:fillColor="?color_feature_liked_you" android:pathData="M64 1a63 63 0 1 0 0 126A63 63 0 1 0 64 1z" /> <path android:fillColor="#FFFFFF" android:pathData="M80.406 ..." /> </vector>
Nos arquivos VectorDrawable, inserimos nomes de variáveis para cores de
fill
associadas a tokens de design por meio de estilos comuns em aplicativos Android.

Vale ressaltar que o Android Studio possui requisitos rígidos para organizar recursos: sem subpastas e letras maiúsculas nos nomes! Então tivemos que criar um novo formato para os nomes dos ícones: no caso de recursos a serem testados, eles se parecem com isso:
ic_icon-name__experiment-name__variant-name
.
Dicionário JSON como uma biblioteca de recursos
Depois que os arquivos de recursos são salvos no formato final, resta apenas coletar todas as metainformações obtidas durante a montagem e salvá-las em um “dicionário” para usar quando os recursos forem importados e usados pela base de código de várias plataformas.
Após extrair uma lista simples de ícones do objeto
assetsMetadata
-o, verificando cada um deles:
- Esse é um recurso regular (por exemplo,
tabbar-livestream
); se sim, então deixe;
- se essa é uma opção para um teste A / B (por exemplo, experiment / tabbar-livestream [variante] ), associamos seu nome, caminho, nomes do teste A / B e variante à propriedade
abtests
o recurso base (no nosso caso, é tabest-livestream ), após o qual excluímos o registro sobre a variante da lista / objeto (apenas o elemento "base" importa);
- se for um "fantasma", exclua o arquivo e remova a entrada da lista / objeto.
Depois de concluir esse processo, o dicionário conterá uma lista de todos os ícones básicos (e seus testes A / B, se houver), e apenas eles. As informações sobre cada um deles incluem o nome, tamanho, caminho e, se o ícone estiver sujeito ao teste A / B, informações sobre suas várias opções.
O dicionário é salvo no formato JSON na pasta de destino da
marca e
plataforma . Aqui, por exemplo, está o arquivo
assets.json gerado para o aplicativo Blendr para Mobile Web:
{ "platform": "mw", "brand": "blendr", "assets": { "badge-feature-like": { "assetname": "badge-feature-like", "path": "assets/badge-feature-like.jsx", "width": 64, "height": 64, "source": "icons_common" }, "navigation-bar-edit": { "assetname": "navigation-bar-edit", "path": "assets/navigation-bar-edit.jsx", "width": 48, "height": 48, "source": "icons_common" }, "tabbar-livestream": { "assetname": "tabbar-livestream", "path": "assets/tabbar-livestream.jsx", "width": 128, "height": 128, "source": "icons_blendr", "abtest": { "this__is_an_experiment": { "control": "assets/this__is_an_experiment/tabbar-livestream__control.jsx", "variant1": "assets/this__is_an_experiment/tabbar-livestream__variant1.jsx", "variant2": "assets/this__is_an_experiment/tabbar-livestream__variant2.jsx" }, "a_second-experiment": { "control": "assets/a_second-experiment/tabbar-livestream__control.jsx", "variantA": "assets/a_second-experiment/tabbar-livestream__variantA.jsx" } } }, ... } }
Agora, resta apenas empacotar todas as pastas de
ativos em arquivos ZIP para facilitar o download.
Sumário
O processo descrito no artigo, da clonagem e manipulação dos arquivos do Sketch à exportação e conversão de recursos para formatos suportados pelas plataformas e salvamento de meta-informações coletadas na biblioteca de recursos, é repetido com todas as marcas anunciadas no script de construção.
Aqui está uma captura de tela mostrando a aparência das pastas
src e
dist após a conclusão do processo:

Nesse estágio, usando um comando simples, você pode fazer upload de todos os recursos (JSON, ZIP e arquivos de recursos) para o armazenamento remoto e disponibilizá-los para todas as plataformas para download e uso na base de código.
Como exatamente as plataformas recebem e processam recursos (usando scripts personalizados criados especificamente para essa finalidade) não vai além do escopo deste artigo. E essa pergunta provavelmente será abordada em um dos posts a seguir por um de meus colegas.
Conclusão (e lições aprendidas)
Eu sempre amei Sketch. Por muitos anos, o programa tem sido a ferramenta padrão para desenvolvedores e designers. Portanto, fiquei muito curioso para aprender ferramentas de integração como
html-sketchapp e outras ferramentas semelhantes que poderíamos usar no fluxo de trabalho e em nossos pipelines.
Eu,
como muitos outros ,
sempre lutei por esse processo (ideal):

No entanto, devo admitir que comecei a duvidar que o Sketch seja uma ferramenta adequada, principalmente considerando o sistema de design. Portanto, comecei a procurar outros serviços, como o Figma com suas APIs abertas e o Framer X com integração conveniente com o React, porque não senti o movimento do Sketch em direção à integração com o código (o que quer que fosse).
Então, esse projeto me convenceu. Não completamente, mas de várias maneiras.
Embora o Sketch não abra suas APIs, o próprio dispositivo da estrutura interna de seus arquivos serve como um tipo de API "não oficial". Os criadores podem usar nomes criptografados ou ocultar chaves em objetos JSON, mas seguem uma convenção de nomenclatura clara, legível e conceitual. Eu não acho que isso seja um acidente.
O fato de que os arquivos do Sketch podem ser gerenciados dessa maneira me abriu muitos desenvolvimentos e melhorias futuros: de plug-ins para verificar o nome, a estilização e a estrutura das camadas de ícones, a integração com nosso Wiki e a documentação de nosso sistema de design (mútuo). Ao criar aplicativos Node no
Electron ou
Carlo , podemos facilitar aos projetistas a conclusão de muitas tarefas rotineiras.
( , ) , Sketch- Cosmos « » — - Cosmos. , ( ; , — ). , — , , .
, Sketch- , , MVP-, . , , . , , -, — , . , .
:
,
. ,
.
, , — . , , , (, A/B-), Node.js Sketch.
! .
(Mobile Web), ,
(Android)
(iOS), .
, ! .