[{"data":1,"prerenderedAt":1574},["ShallowReactive",2],{"biblioteca-\u002Fbiblioteca\u002Fimagenes-con-tu-marca-desde-vscode":3},{"id":4,"title":5,"author":6,"body":7,"cover":1558,"description":1559,"extension":1560,"meta":1561,"navigation":437,"nivel":1562,"path":1563,"publishedAt":1564,"seo":1565,"stem":1566,"tags":1567,"__hash__":1573},"biblioteca\u002Fbiblioteca\u002Fimagenes-con-tu-marca-desde-vscode.md","Genera imágenes con tu marca desde VS Code","Miguel Santa",{"type":8,"value":9,"toc":1534},"minimark",[10,18,36,41,48,51,54,57,89,92,95,99,102,105,108,137,144,147,149,153,166,169,191,282,336,339,341,345,355,362,365,514,517,519,523,529,535,683,688,694,704,710,721,723,734,737,744,747,910,920,926,929,967,970,1147,1176,1178,1182,1189,1211,1214,1222,1225,1229,1232,1238,1248,1250,1254,1257,1264,1294,1296,1302,1305,1326,1328,1332,1335,1343,1349,1365,1368,1393,1395,1399,1406,1460,1462,1466,1494,1496,1500,1503,1515,1517,1521,1530],[11,12],"youtube-cta",{"channel":13,"subtitle":14,"title":15,"url":16,"video-id":17},"@Santa_lA","Te muestro el flujo entero: cerebro de marca, key en Keychain y Claude Code invocando el script desde VS Code.","Esta guía va con video en el canal","https:\u002F\u002Fwww.youtube.com\u002F@Santa_lA","pendiente",[19,20,23,27,33],"callout",{"title":21,"type":22},"¿Apurado? Que Claude te haga un resumen rápido.","claude",[24,25,26],"p",{},"Copia el link de esta página y pégalo en Claude (claude.ai, el escritorio o la app). Le pides algo así:",[24,28,29],{},[30,31,32],"strong",{},"\"Resúmeme esta guía en 5 puntos y dime qué tengo que tener instalado antes de empezar.\"",[24,34,35],{},"En 30 segundos tienes la lectura corta. Después te devuelves a la sección que te llame.",[37,38,40],"h2",{"id":39},"_1-el-problema-cada-imagen-arranca-de-cero","1 · El problema · cada imagen arranca de cero",[24,42,43,44,47],{},"Generaste tu primera imagen con IA. Quedó linda. La segunda no se parece a la primera. La tercera tampoco. Todas se ven hechas por máquina, ninguna se ve hecha ",[30,45,46],{},"para tu marca",".",[24,49,50],{},"Lo que falta no es el modelo. El modelo está bien. Lo que falta es contexto. Tu paleta, tu tono, tu público, lo que sí muestras y lo que nunca. Eso no vive en ninguna parte que el modelo pueda leer.",[24,52,53],{},"Cada vez tecleas el prompt de cero. Cada vez se te olvida un detalle. Cada vez sale distinta.",[24,55,56],{},"Este patrón cierra esa fuga. Tres piezas:",[58,59,60,73,83],"ul",{},[61,62,63,64,67,68,72],"li",{},"Un ",[30,65,66],{},"cerebro de marca"," en un archivo ",[69,70,71],"code",{},".md"," que viaja con cada prompt.",[61,74,75,76,79,80,47],{},"Tu ",[30,77,78],{},"API key"," guardada en el Keychain de macOS, no en un ",[69,81,82],{},".env",[61,84,63,85,88],{},[30,86,87],{},"script de Python"," que junta las dos cosas y llama a Gemini.",[24,90,91],{},"Lo invocas desde tu terminal. O le pides a Claude Code dentro de VS Code que lo invoque por ti. Al final tienes imágenes consistentes con tu marca, sin repetir tu storytelling cada vez.",[93,94],"hr",{},[37,96,98],{"id":97},"_2-la-idea-cerebro-key-cliente","2 · La idea · cerebro · key · cliente",[24,100,101],{},"Antes del paso a paso, mira el flujo de lejos.",[103,104],"diagram-cerebro-gemini",{},[24,106,107],{},"Cuatro piezas, una sola dirección:",[58,109,110,119,125,131],{},[61,111,112,115,116,118],{},[30,113,114],{},"Cerebro (capa 1)."," Un ",[69,117,71],{}," que tiene tu marca por escrito. Es la fuente.",[61,120,121,124],{},[30,122,123],{},"Cliente (capa 2)."," Un script Python que lee el cerebro, lee tu prompt y lee la key.",[61,126,127,130],{},[30,128,129],{},"Modelo (capa 3)."," Gemini recibe el cerebro como contexto y tu petición como instrucción.",[61,132,133,136],{},[30,134,135],{},"Salida (capa 4)."," Un PNG que ya viene con tu paleta y tu estilo.",[24,138,139,140,143],{},"La pieza opcional es la ",[30,141,142],{},"referencia visual",". Si pasas una foto local (tu producto, tu cara, una textura), Gemini la usa como ancla y te devuelve variaciones que parten desde ahí.",[24,145,146],{},"El cerebro no es un prompt largo que copias y pegas cada vez. Vive en un archivo. El script lo concatena solo. Tú nunca te peleas con el contexto.",[93,148],{},[37,150,152],{"id":151},"_3-tu-key-de-gemini-3-líneas","3 · Tu key de Gemini · 3 líneas",[19,154,157],{"title":155,"type":156},"Si esto del Keychain te suena chino","info",[24,158,159,160,165],{},"Pasa primero por la ",[161,162,164],"a",{"href":163},"\u002Fbiblioteca\u002Fguarda-tus-tokens-sin-filtrarlos","guía base de tokens"," y vuelves. Explica el porqué con números reales (Toyota, 5 años filtrado) y cubre Mac, Windows y Linux. Esta sección asume que ya entiendes el patrón.",[24,167,168],{},"Pídela una sola vez en Google AI Studio.",[170,171,174],"step-card",{"number":172,"title":173},"1","Sacar la key",[24,175,176,177,182,183,186,187,190],{},"Entra a ",[161,178,179],{"href":179,"rel":180},"https:\u002F\u002Faistudio.google.com\u002Fapp\u002Fapikey",[181],"nofollow",". Si no tienes proyecto, crea uno. Click en ",[30,184,185],{},"Create API key",". Copia el valor (empieza con ",[69,188,189],{},"AIza...",").",[170,192,195,206,271],{"number":193,"title":194},"2","Guardarla en Keychain",[24,196,197,198,201,202,205],{},"Desde tu terminal (Mac). El ",[69,199,200],{},"-w"," sin valor te pregunta el token en interactivo, así no queda en ",[69,203,204],{},".zsh_history",":",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-bash shiki shiki-themes github-light github-dark","security add-generic-password \\\n  -a \"santaia\" \\\n  -s \"santaia:gemini-key\" \\\n  -l \"Gemini API\" \\\n  -w\n","bash","",[69,214,215,232,243,254,265],{"__ignoreMap":212},[216,217,220,224,228],"span",{"class":218,"line":219},"line",1,[216,221,223],{"class":222},"sScJk","security",[216,225,227],{"class":226},"sZZnC"," add-generic-password",[216,229,231],{"class":230},"sj4cs"," \\\n",[216,233,235,238,241],{"class":218,"line":234},2,[216,236,237],{"class":230},"  -a",[216,239,240],{"class":226}," \"santaia\"",[216,242,231],{"class":230},[216,244,246,249,252],{"class":218,"line":245},3,[216,247,248],{"class":230},"  -s",[216,250,251],{"class":226}," \"santaia:gemini-key\"",[216,253,231],{"class":230},[216,255,257,260,263],{"class":218,"line":256},4,[216,258,259],{"class":230},"  -l",[216,261,262],{"class":226}," \"Gemini API\"",[216,264,231],{"class":230},[216,266,268],{"class":218,"line":267},5,[216,269,270],{"class":230},"  -w\n",[24,272,273,274,277,278,281],{},"Cambia ",[69,275,276],{},"santaia"," por el nombre que uses tú. Ese mismo nombre va en el argumento ",[69,279,280],{},"--project"," del script.",[170,283,286,329],{"number":284,"title":285},"3","Verificar que quedó",[207,287,289],{"className":209,"code":288,"language":211,"meta":212,"style":212},"security find-generic-password -s \"santaia:gemini-key\" -w | head -c 12 && echo \"...\"\n",[69,290,291],{"__ignoreMap":212},[216,292,293,295,298,301,303,306,310,313,316,319,323,326],{"class":218,"line":219},[216,294,223],{"class":222},[216,296,297],{"class":226}," find-generic-password",[216,299,300],{"class":230}," -s",[216,302,251],{"class":226},[216,304,305],{"class":230}," -w",[216,307,309],{"class":308},"szBVR"," |",[216,311,312],{"class":222}," head",[216,314,315],{"class":230}," -c",[216,317,318],{"class":230}," 12",[216,320,322],{"class":321},"sVt8B"," && ",[216,324,325],{"class":230},"echo",[216,327,328],{"class":226}," \"...\"\n",[24,330,331,332,335],{},"Si imprime los primeros 12 caracteres seguido de ",[69,333,334],{},"...",", está guardada. Listo.",[24,337,338],{},"Ya no la necesitas en ningún archivo. El script la pide al Keychain solo cuando va a llamar al modelo.",[93,340],{},[37,342,344],{"id":343},"_4-la-ficha-tipo-jarvis-de-la-key","4 · La ficha tipo JARVIS de la key",[24,346,347,348,351,352,47],{},"El patrón completo no es solo guardar la key. Es ",[30,349,350],{},"dejar metadata"," de qué key es, dónde vive y cómo se rota. Yo lo hago con un archivo por servicio en una carpeta llamada ",[69,353,354],{},"09-CREDENTIALS\u002F",[24,356,357,358,361],{},"La regla es simple: ",[30,359,360],{},"metadata en el .md, valor en el Keychain",". Nunca al revés.",[24,363,364],{},"Esta es la ficha tipo que uso (la versión vacía está en el starter que descargas más abajo):",[207,366,370],{"className":367,"code":368,"language":369,"meta":212,"style":212},"language-markdown shiki shiki-themes github-light github-dark","---\nservicio: Google Gemini API Key\ncuenta: tu-email@gmail.com\nproyectos_que_lo_usan:\n  - mi-proyecto\nkeychain_service: mi-proyecto:gemini-key\nkeychain_account: mi-proyecto\nfecha_guardado: 2026-05-24\nexpira: no expira (revocable manualmente)\nconsole_url: https:\u002F\u002Faistudio.google.com\u002Fapp\u002Fapikey\n---\n\n# Gemini API Key · mi-proyecto\n\nUna línea: para qué se usa en este proyecto.\n\n## Cómo guardarla, leerla, borrarla\n[comandos de security]\n\n## Si se filtra\n1. Revoca en console_url\n2. Genera nueva\n3. delete del Keychain\n4. add de nuevo\n5. Actualiza fecha_guardado\n","markdown",[69,371,372,377,382,387,392,397,403,409,415,421,427,432,439,445,450,456,461,467,473,478,484,490,496,502,508],{"__ignoreMap":212},[216,373,374],{"class":218,"line":219},[216,375,376],{},"---\n",[216,378,379],{"class":218,"line":234},[216,380,381],{},"servicio: Google Gemini API Key\n",[216,383,384],{"class":218,"line":245},[216,385,386],{},"cuenta: tu-email@gmail.com\n",[216,388,389],{"class":218,"line":256},[216,390,391],{},"proyectos_que_lo_usan:\n",[216,393,394],{"class":218,"line":267},[216,395,396],{},"  - mi-proyecto\n",[216,398,400],{"class":218,"line":399},6,[216,401,402],{},"keychain_service: mi-proyecto:gemini-key\n",[216,404,406],{"class":218,"line":405},7,[216,407,408],{},"keychain_account: mi-proyecto\n",[216,410,412],{"class":218,"line":411},8,[216,413,414],{},"fecha_guardado: 2026-05-24\n",[216,416,418],{"class":218,"line":417},9,[216,419,420],{},"expira: no expira (revocable manualmente)\n",[216,422,424],{"class":218,"line":423},10,[216,425,426],{},"console_url: https:\u002F\u002Faistudio.google.com\u002Fapp\u002Fapikey\n",[216,428,430],{"class":218,"line":429},11,[216,431,376],{},[216,433,435],{"class":218,"line":434},12,[216,436,438],{"emptyLinePlaceholder":437},true,"\n",[216,440,442],{"class":218,"line":441},13,[216,443,444],{},"# Gemini API Key · mi-proyecto\n",[216,446,448],{"class":218,"line":447},14,[216,449,438],{"emptyLinePlaceholder":437},[216,451,453],{"class":218,"line":452},15,[216,454,455],{},"Una línea: para qué se usa en este proyecto.\n",[216,457,459],{"class":218,"line":458},16,[216,460,438],{"emptyLinePlaceholder":437},[216,462,464],{"class":218,"line":463},17,[216,465,466],{},"## Cómo guardarla, leerla, borrarla\n",[216,468,470],{"class":218,"line":469},18,[216,471,472],{},"[comandos de security]\n",[216,474,476],{"class":218,"line":475},19,[216,477,438],{"emptyLinePlaceholder":437},[216,479,481],{"class":218,"line":480},20,[216,482,483],{},"## Si se filtra\n",[216,485,487],{"class":218,"line":486},21,[216,488,489],{},"1. Revoca en console_url\n",[216,491,493],{"class":218,"line":492},22,[216,494,495],{},"2. Genera nueva\n",[216,497,499],{"class":218,"line":498},23,[216,500,501],{},"3. delete del Keychain\n",[216,503,505],{"class":218,"line":504},24,[216,506,507],{},"4. add de nuevo\n",[216,509,511],{"class":218,"line":510},25,[216,512,513],{},"5. Actualiza fecha_guardado\n",[24,515,516],{},"¿Por qué este patrón importa? Porque dentro de 6 meses, cuando rotes la key o entre alguien nuevo a tu equipo, este archivo es el que responde \"dónde está esa cosa\". El Keychain guarda el valor, la ficha guarda la historia.",[93,518],{},[37,520,522],{"id":521},"_5-el-cerebro-de-marca-qué-va-dentro","5 · El cerebro de marca · qué va dentro",[24,524,525,526,528],{},"El cerebro es un ",[69,527,71],{}," con frontmatter. Lo que escribas ahí viaja con cada prompt. Mientras más concreto, más consistente sale la imagen.",[24,530,531,532,205],{},"Para el starter inventé una marca demo, una academia ficticia de panadería casera llamada ",[30,533,534],{},"Levadura Lenta",[207,536,540],{"className":537,"code":538,"language":539,"meta":212,"style":212},"language-yaml shiki shiki-themes github-light github-dark","---\nmarca: Levadura Lenta\nmision: enseñar panadería casera a gente que nunca ha amasado\nvoz: cálida, paciente, sin tecnicismos\npaleta:\n  primario: \"#C97B4A\"\n  secundario: \"#F4E4C1\"\n  acento: \"#3D2817\"\npublico: principiantes 25-45 años, viven en ciudad\nestilo_visual: fotografía cálida con grano, luz dorada, manos visibles, ingredientes humildes\ndo:\n  - mostrar el proceso, no solo el resultado\n  - personas reales, manos sucias de harina\ndont:\n  - planos perfectos de revistas\n  - tipografía cursiva exagerada\n---\n","yaml",[69,541,542,546,558,568,578,586,596,606,616,626,636,643,651,658,665,672,679],{"__ignoreMap":212},[216,543,544],{"class":218,"line":219},[216,545,376],{"class":222},[216,547,548,552,555],{"class":218,"line":234},[216,549,551],{"class":550},"s9eBZ","marca",[216,553,554],{"class":321},": ",[216,556,557],{"class":226},"Levadura Lenta\n",[216,559,560,563,565],{"class":218,"line":245},[216,561,562],{"class":550},"mision",[216,564,554],{"class":321},[216,566,567],{"class":226},"enseñar panadería casera a gente que nunca ha amasado\n",[216,569,570,573,575],{"class":218,"line":256},[216,571,572],{"class":550},"voz",[216,574,554],{"class":321},[216,576,577],{"class":226},"cálida, paciente, sin tecnicismos\n",[216,579,580,583],{"class":218,"line":267},[216,581,582],{"class":550},"paleta",[216,584,585],{"class":321},":\n",[216,587,588,591,593],{"class":218,"line":399},[216,589,590],{"class":550},"  primario",[216,592,554],{"class":321},[216,594,595],{"class":226},"\"#C97B4A\"\n",[216,597,598,601,603],{"class":218,"line":405},[216,599,600],{"class":550},"  secundario",[216,602,554],{"class":321},[216,604,605],{"class":226},"\"#F4E4C1\"\n",[216,607,608,611,613],{"class":218,"line":411},[216,609,610],{"class":550},"  acento",[216,612,554],{"class":321},[216,614,615],{"class":226},"\"#3D2817\"\n",[216,617,618,621,623],{"class":218,"line":417},[216,619,620],{"class":550},"publico",[216,622,554],{"class":321},[216,624,625],{"class":226},"principiantes 25-45 años, viven en ciudad\n",[216,627,628,631,633],{"class":218,"line":423},[216,629,630],{"class":550},"estilo_visual",[216,632,554],{"class":321},[216,634,635],{"class":226},"fotografía cálida con grano, luz dorada, manos visibles, ingredientes humildes\n",[216,637,638,641],{"class":218,"line":429},[216,639,640],{"class":550},"do",[216,642,585],{"class":321},[216,644,645,648],{"class":218,"line":434},[216,646,647],{"class":321},"  - ",[216,649,650],{"class":226},"mostrar el proceso, no solo el resultado\n",[216,652,653,655],{"class":218,"line":441},[216,654,647],{"class":321},[216,656,657],{"class":226},"personas reales, manos sucias de harina\n",[216,659,660,663],{"class":218,"line":447},[216,661,662],{"class":550},"dont",[216,664,585],{"class":321},[216,666,667,669],{"class":218,"line":452},[216,668,647],{"class":321},[216,670,671],{"class":226},"planos perfectos de revistas\n",[216,673,674,676],{"class":218,"line":458},[216,675,647],{"class":321},[216,677,678],{"class":226},"tipografía cursiva exagerada\n",[216,680,681],{"class":218,"line":463},[216,682,376],{"class":222},[684,685,687],"h3",{"id":686},"las-3-reglas-para-escribir-un-buen-cerebro","Las 3 reglas para escribir un buen cerebro",[170,689,691],{"number":172,"title":690},"Sé específico, no decorativo",[24,692,693],{},"\"Fondo neutro\" no le dice nada al modelo. \"Mesa de madera oscura con luz lateral suave\" sí. Si una palabra del cerebro la podrías reemplazar por su opuesto sin que cambie nada, sobra.",[170,695,697],{"number":193,"title":696},"Hex codes, no nombres de colores",[24,698,699,700,703],{},"\"Naranja terracota\" lo interpreta cada modelo distinto. ",[69,701,702],{},"#C97B4A"," no. Nombra los colores por su hex en el frontmatter. El modelo los respeta.",[170,705,707],{"number":284,"title":706},"Lista 2 o 3 dont claros",[24,708,709],{},"Las prohibiciones son lo que más diferencia tu marca de la imagen genérica. \"Sin tipografía cursiva exagerada\" te ahorra 30 iteraciones contra el default romántico de stock.",[19,711,714],{"title":712,"type":713},"Itera el cerebro, no el prompt","tip",[24,715,716,717,720],{},"La primera versión del cerebro te va a quedar incompleta. Eso es normal. Cuando te salga una imagen que no quieres, no reescribas el prompt: ",[30,718,719],{},"abre el cerebro y agrega una regla",". En dos semanas el cerebro queda afinado y los prompts se vuelven cortos.",[93,722],{},[37,724,726,727,730,731],{"id":725},"_6-el-wrapper-keychainpy-y-generate_imagepy","6 · El wrapper · ",[69,728,729],{},"keychain.py"," y ",[69,732,733],{},"generate_image.py",[24,735,736],{},"Dos piezas de código. La primera lee la key. La segunda llama a Gemini.",[684,738,740,743],{"id":739},"sharedsecretskeychainpy-wrapper-de-keychain",[69,741,742],{},"shared\u002Fsecrets\u002Fkeychain.py"," · wrapper de Keychain",[24,745,746],{},"Lee, guarda y borra secretos del Keychain de macOS. Lo importas desde el script principal. Si la key no existe, te dice exactamente qué comando correr para guardarla.",[207,748,752],{"className":749,"code":750,"language":751,"meta":212,"style":212},"language-python shiki shiki-themes github-light github-dark","from __future__ import annotations\nimport subprocess\n\nDEFAULT_PROJECT = \"santaia\"\n\ndef _service_name(key: str, project: str) -> str:\n    if \":\" in key:\n        return key\n    return f\"{project}:{key}\"\n\ndef get_secret(key: str, project: str = DEFAULT_PROJECT) -> str | None:\n    try:\n        result = subprocess.run(\n            [\"security\", \"find-generic-password\",\n             \"-s\", _service_name(key, project), \"-w\"],\n            capture_output=True, text=True, check=False,\n        )\n    except FileNotFoundError:\n        return None\n    return result.stdout.strip() if result.returncode == 0 else None\n\ndef require_secret(key: str, project: str = DEFAULT_PROJECT) -> str:\n    value = get_secret(key, project=project)\n    if value is None:\n        service = _service_name(key, project)\n        raise RuntimeError(\n            f\"Secret '{service}' no encontrado en Keychain.\\n\"\n            f\"Guárdalo con: security add-generic-password \"\n            f\"-s {service} -a {project} -w '\u003Cvalor>' -U\"\n        )\n    return value\n","python",[69,753,754,759,764,768,773,777,782,787,792,797,801,806,811,816,821,826,831,836,841,846,851,855,860,865,870,875,881,887,893,899,904],{"__ignoreMap":212},[216,755,756],{"class":218,"line":219},[216,757,758],{},"from __future__ import annotations\n",[216,760,761],{"class":218,"line":234},[216,762,763],{},"import subprocess\n",[216,765,766],{"class":218,"line":245},[216,767,438],{"emptyLinePlaceholder":437},[216,769,770],{"class":218,"line":256},[216,771,772],{},"DEFAULT_PROJECT = \"santaia\"\n",[216,774,775],{"class":218,"line":267},[216,776,438],{"emptyLinePlaceholder":437},[216,778,779],{"class":218,"line":399},[216,780,781],{},"def _service_name(key: str, project: str) -> str:\n",[216,783,784],{"class":218,"line":405},[216,785,786],{},"    if \":\" in key:\n",[216,788,789],{"class":218,"line":411},[216,790,791],{},"        return key\n",[216,793,794],{"class":218,"line":417},[216,795,796],{},"    return f\"{project}:{key}\"\n",[216,798,799],{"class":218,"line":423},[216,800,438],{"emptyLinePlaceholder":437},[216,802,803],{"class":218,"line":429},[216,804,805],{},"def get_secret(key: str, project: str = DEFAULT_PROJECT) -> str | None:\n",[216,807,808],{"class":218,"line":434},[216,809,810],{},"    try:\n",[216,812,813],{"class":218,"line":441},[216,814,815],{},"        result = subprocess.run(\n",[216,817,818],{"class":218,"line":447},[216,819,820],{},"            [\"security\", \"find-generic-password\",\n",[216,822,823],{"class":218,"line":452},[216,824,825],{},"             \"-s\", _service_name(key, project), \"-w\"],\n",[216,827,828],{"class":218,"line":458},[216,829,830],{},"            capture_output=True, text=True, check=False,\n",[216,832,833],{"class":218,"line":463},[216,834,835],{},"        )\n",[216,837,838],{"class":218,"line":469},[216,839,840],{},"    except FileNotFoundError:\n",[216,842,843],{"class":218,"line":475},[216,844,845],{},"        return None\n",[216,847,848],{"class":218,"line":480},[216,849,850],{},"    return result.stdout.strip() if result.returncode == 0 else None\n",[216,852,853],{"class":218,"line":486},[216,854,438],{"emptyLinePlaceholder":437},[216,856,857],{"class":218,"line":492},[216,858,859],{},"def require_secret(key: str, project: str = DEFAULT_PROJECT) -> str:\n",[216,861,862],{"class":218,"line":498},[216,863,864],{},"    value = get_secret(key, project=project)\n",[216,866,867],{"class":218,"line":504},[216,868,869],{},"    if value is None:\n",[216,871,872],{"class":218,"line":510},[216,873,874],{},"        service = _service_name(key, project)\n",[216,876,878],{"class":218,"line":877},26,[216,879,880],{},"        raise RuntimeError(\n",[216,882,884],{"class":218,"line":883},27,[216,885,886],{},"            f\"Secret '{service}' no encontrado en Keychain.\\n\"\n",[216,888,890],{"class":218,"line":889},28,[216,891,892],{},"            f\"Guárdalo con: security add-generic-password \"\n",[216,894,896],{"class":218,"line":895},29,[216,897,898],{},"            f\"-s {service} -a {project} -w '\u003Cvalor>' -U\"\n",[216,900,902],{"class":218,"line":901},30,[216,903,835],{},[216,905,907],{"class":218,"line":906},31,[216,908,909],{},"    return value\n",[24,911,912,913,730,916,919],{},"(En el starter va completo con ",[69,914,915],{},"set_secret",[69,917,918],{},"delete_secret"," también.)",[684,921,923,925],{"id":922},"generate_imagepy-el-script-cli",[69,924,733],{}," · el script CLI",[24,927,928],{},"Argumentos:",[58,930,931,937,943,952,961],{},[61,932,933,936],{},[69,934,935],{},"--prompt \"texto\"",": qué quieres ver (obligatorio).",[61,938,939,942],{},[69,940,941],{},"--ref foto.jpg",": imagen local de referencia (opcional, activa modo B).",[61,944,945,948,949,190],{},[69,946,947],{},"--brain brand_brain.md",": cerebro de marca (default ",[69,950,951],{},".\u002Fbrand_brain.md",[61,953,954,957,958,190],{},[69,955,956],{},"--out salida.png",": ruta del PNG (default: ",[69,959,960],{},"out_\u003Ctimestamp>.png",[61,962,963,966],{},[69,964,965],{},"--project santaia",": prefijo de tu proyecto en Keychain.",[24,968,969],{},"El flujo es directo:",[207,971,973],{"className":749,"code":972,"language":751,"meta":212,"style":212},"from google import genai\nfrom google.genai import types\nfrom PIL import Image\nfrom shared.secrets.keychain import require_secret\n\nMODEL = \"gemini-3-pro-image-preview\"\n\napi_key = require_secret(\"gemini-key\", project=args.project)\nclient = genai.Client(api_key=api_key)\n\nbrain_text = Path(args.brain).read_text(encoding=\"utf-8\")\nfull_prompt = (\n    \"Generate an image following the brand brain below as visual + tone \"\n    \"context. The brand brain defines colors (use the hex codes exactly), \"\n    \"visual style, do\u002Fdon't and audience.\\n\\n\"\n    f\"=== BRAND BRAIN ===\\n{brain_text}\\n=== END BRAND BRAIN ===\\n\\n\"\n    f\"User request: {args.prompt}\"\n)\n\ncontents = []\nif args.ref:\n    contents.append(types.Part.from_bytes(\n        data=Path(args.ref).read_bytes(),\n        mime_type=\"image\u002Fjpeg\",\n    ))\ncontents.append(full_prompt)\n\nresp = client.models.generate_content(\n    model=MODEL,\n    contents=contents,\n    config=types.GenerateContentConfig(response_modalities=[\"IMAGE\"]),\n)\n\nraw = resp.candidates[0].content.parts[0].inline_data.data\nImage.open(io.BytesIO(raw)).save(out_path, format=\"PNG\")\n",[69,974,975,980,985,990,995,999,1004,1008,1013,1018,1022,1027,1032,1037,1042,1047,1052,1057,1062,1066,1071,1076,1081,1086,1091,1096,1101,1105,1110,1115,1120,1125,1130,1135,1141],{"__ignoreMap":212},[216,976,977],{"class":218,"line":219},[216,978,979],{},"from google import genai\n",[216,981,982],{"class":218,"line":234},[216,983,984],{},"from google.genai import types\n",[216,986,987],{"class":218,"line":245},[216,988,989],{},"from PIL import Image\n",[216,991,992],{"class":218,"line":256},[216,993,994],{},"from shared.secrets.keychain import require_secret\n",[216,996,997],{"class":218,"line":267},[216,998,438],{"emptyLinePlaceholder":437},[216,1000,1001],{"class":218,"line":399},[216,1002,1003],{},"MODEL = \"gemini-3-pro-image-preview\"\n",[216,1005,1006],{"class":218,"line":405},[216,1007,438],{"emptyLinePlaceholder":437},[216,1009,1010],{"class":218,"line":411},[216,1011,1012],{},"api_key = require_secret(\"gemini-key\", project=args.project)\n",[216,1014,1015],{"class":218,"line":417},[216,1016,1017],{},"client = genai.Client(api_key=api_key)\n",[216,1019,1020],{"class":218,"line":423},[216,1021,438],{"emptyLinePlaceholder":437},[216,1023,1024],{"class":218,"line":429},[216,1025,1026],{},"brain_text = Path(args.brain).read_text(encoding=\"utf-8\")\n",[216,1028,1029],{"class":218,"line":434},[216,1030,1031],{},"full_prompt = (\n",[216,1033,1034],{"class":218,"line":441},[216,1035,1036],{},"    \"Generate an image following the brand brain below as visual + tone \"\n",[216,1038,1039],{"class":218,"line":447},[216,1040,1041],{},"    \"context. The brand brain defines colors (use the hex codes exactly), \"\n",[216,1043,1044],{"class":218,"line":452},[216,1045,1046],{},"    \"visual style, do\u002Fdon't and audience.\\n\\n\"\n",[216,1048,1049],{"class":218,"line":458},[216,1050,1051],{},"    f\"=== BRAND BRAIN ===\\n{brain_text}\\n=== END BRAND BRAIN ===\\n\\n\"\n",[216,1053,1054],{"class":218,"line":463},[216,1055,1056],{},"    f\"User request: {args.prompt}\"\n",[216,1058,1059],{"class":218,"line":469},[216,1060,1061],{},")\n",[216,1063,1064],{"class":218,"line":475},[216,1065,438],{"emptyLinePlaceholder":437},[216,1067,1068],{"class":218,"line":480},[216,1069,1070],{},"contents = []\n",[216,1072,1073],{"class":218,"line":486},[216,1074,1075],{},"if args.ref:\n",[216,1077,1078],{"class":218,"line":492},[216,1079,1080],{},"    contents.append(types.Part.from_bytes(\n",[216,1082,1083],{"class":218,"line":498},[216,1084,1085],{},"        data=Path(args.ref).read_bytes(),\n",[216,1087,1088],{"class":218,"line":504},[216,1089,1090],{},"        mime_type=\"image\u002Fjpeg\",\n",[216,1092,1093],{"class":218,"line":510},[216,1094,1095],{},"    ))\n",[216,1097,1098],{"class":218,"line":877},[216,1099,1100],{},"contents.append(full_prompt)\n",[216,1102,1103],{"class":218,"line":883},[216,1104,438],{"emptyLinePlaceholder":437},[216,1106,1107],{"class":218,"line":889},[216,1108,1109],{},"resp = client.models.generate_content(\n",[216,1111,1112],{"class":218,"line":895},[216,1113,1114],{},"    model=MODEL,\n",[216,1116,1117],{"class":218,"line":901},[216,1118,1119],{},"    contents=contents,\n",[216,1121,1122],{"class":218,"line":906},[216,1123,1124],{},"    config=types.GenerateContentConfig(response_modalities=[\"IMAGE\"]),\n",[216,1126,1128],{"class":218,"line":1127},32,[216,1129,1061],{},[216,1131,1133],{"class":218,"line":1132},33,[216,1134,438],{"emptyLinePlaceholder":437},[216,1136,1138],{"class":218,"line":1137},34,[216,1139,1140],{},"raw = resp.candidates[0].content.parts[0].inline_data.data\n",[216,1142,1144],{"class":218,"line":1143},35,[216,1145,1146],{},"Image.open(io.BytesIO(raw)).save(out_path, format=\"PNG\")\n",[19,1148,1150,1165],{"title":1149,"type":156},"Qué SDK y qué modelo",[24,1151,1152,1153,1156,1157,1160,1161,1164],{},"Uso el SDK nuevo ",[69,1154,1155],{},"google-genai"," (no el viejo ",[69,1158,1159],{},"google-generativeai","). El nuevo es el que recomienda Google de aquí en adelante y el que acepta ",[69,1162,1163],{},"response_modalities=[\"IMAGE\"]"," para forzar salida de imagen.",[24,1166,1167,1168,1171,1172,1175],{},"El modelo ",[69,1169,1170],{},"gemini-3-pro-image-preview"," es el que responde con más fidelidad a referencias locales hoy. Si Google libera uno más reciente, cambias la constante ",[69,1173,1174],{},"MODEL"," y listo.",[93,1177],{},[37,1179,1181],{"id":1180},"_7-modo-a-texto-a-imagen","7 · Modo A · texto a imagen",[24,1183,1184,1185,1188],{},"Una vez instalas dependencias (",[69,1186,1187],{},"pip install google-genai pillow","), la primera invocación es esta:",[207,1190,1192],{"className":209,"code":1191,"language":211,"meta":212,"style":212},"python generate_image.py \\\n  --prompt \"una hogaza de pan recién horneada sobre una mesa de madera oscura, luz lateral, vapor saliendo\"\n",[69,1193,1194,1203],{"__ignoreMap":212},[216,1195,1196,1198,1201],{"class":218,"line":219},[216,1197,751],{"class":222},[216,1199,1200],{"class":226}," generate_image.py",[216,1202,231],{"class":230},[216,1204,1205,1208],{"class":218,"line":234},[216,1206,1207],{"class":230},"  --prompt",[216,1209,1210],{"class":226}," \"una hogaza de pan recién horneada sobre una mesa de madera oscura, luz lateral, vapor saliendo\"\n",[24,1212,1213],{},"Output:",[207,1215,1220],{"className":1216,"code":1218,"language":1219},[1217],"language-text","[modelo] gemini-3-pro-image-preview\n[cerebro] brand_brain.md\n[gemini] generando ...\n[ok] guardada -> out_20260524-181830.png  (1024x1024)\n","text",[69,1221,1218],{"__ignoreMap":212},[24,1223,1224],{},"La imagen sale con la paleta y el mood del cerebro. Sin que tuvieras que repetir \"estilo cálido, grano, manos visibles\" en el prompt. Eso ya viajó adentro.",[684,1226,1228],{"id":1227},"cuando-el-resultado-no-es-lo-que-querías","Cuando el resultado no es lo que querías",[24,1230,1231],{},"Dos caminos, en este orden:",[170,1233,1235],{"number":172,"title":1234},"Ajusta el prompt si fue un error de petición",[24,1236,1237],{},"Pediste \"pan\" y querías \"croissant\". Cambias el prompt y vuelves a correr.",[170,1239,1241],{"number":193,"title":1240},"Ajusta el cerebro si el problema se repite",[24,1242,1243,1244,1247],{},"Pediste \"pan\" y siempre te sale en un plano cenital perfecto de revista. El problema no es el prompt: es que tu cerebro no tiene ",[69,1245,1246],{},"dont: planos cenitales"," todavía. Edítalo. La siguiente vez sale distinto.",[93,1249],{},[37,1251,1253],{"id":1252},"_8-modo-b-imagen-a-imagen-con-foto-local","8 · Modo B · imagen a imagen con foto local",[24,1255,1256],{},"Aquí es donde la mayoría de APIs te dejan colgado. Kie.ai, por ejemplo, solo recibe URLs públicas. No puedes pasarle una foto que vive en tu disco.",[24,1258,1259,1260,1263],{},"Gemini sí. Le pasas la ruta local con ",[69,1261,1262],{},"--ref"," y la usa como ancla visual:",[207,1265,1267],{"className":209,"code":1266,"language":211,"meta":212,"style":212},"python generate_image.py \\\n  --prompt \"el mismo pan pero cortado a la mitad, mostrando la miga\" \\\n  --ref .\u002Fmi-hogaza.jpg\n",[69,1268,1269,1277,1286],{"__ignoreMap":212},[216,1270,1271,1273,1275],{"class":218,"line":219},[216,1272,751],{"class":222},[216,1274,1200],{"class":226},[216,1276,231],{"class":230},[216,1278,1279,1281,1284],{"class":218,"line":234},[216,1280,1207],{"class":230},[216,1282,1283],{"class":226}," \"el mismo pan pero cortado a la mitad, mostrando la miga\"",[216,1285,231],{"class":230},[216,1287,1288,1291],{"class":218,"line":245},[216,1289,1290],{"class":230},"  --ref",[216,1292,1293],{"class":226}," .\u002Fmi-hogaza.jpg\n",[24,1295,1213],{},[207,1297,1300],{"className":1298,"code":1299,"language":1219},[1217],"[ref] cargada mi-hogaza.jpg\n[modelo] gemini-3-pro-image-preview\n[cerebro] brand_brain.md\n[gemini] generando ...\n[ok] guardada -> out_20260524-182112.png  (1024x1024)\n",[69,1301,1299],{"__ignoreMap":212},[24,1303,1304],{},"El modelo recibe tres cosas en orden: la imagen de referencia, el cerebro de marca, tu petición. Gemini usa la foto como composición base y la regenera siguiendo el cerebro.",[19,1306,1309,1312,1323],{"title":1307,"type":1308},"Lo que no esperes del modo B","warning",[24,1310,1311],{},"Esto no es Photoshop. No le pidas \"quita ese pixel\" o \"muévele el ojo 2mm a la izquierda\". Sirve para:",[58,1313,1314,1317,1320],{},[61,1315,1316],{},"Variaciones del mismo objeto en otros ángulos\u002Fescenarios.",[61,1318,1319],{},"Cambiar el mood o la paleta de una foto base.",[61,1321,1322],{},"Generar piezas que comparten un anclaje visual.",[24,1324,1325],{},"Para edición pixel-perfect, necesitas otra cosa (Photoshop, Lightroom, o flujos de Stable Diffusion con inpainting). El modo B es para mantener consistencia visual, no para retoque fino.",[93,1327],{},[37,1329,1331],{"id":1330},"_9-que-claude-code-lo-invoque-por-ti","9 · Que Claude Code lo invoque por ti",[24,1333,1334],{},"Hasta acá invocas el script tú, desde tu terminal. El siguiente paso es no escribir el comando.",[24,1336,1337,1338,1342],{},"Abres VS Code en la carpeta del starter. Tienes Claude Code corriendo (si no, mira ",[161,1339,1341],{"href":1340},"\u002Fbiblioteca\u002Fclaude-code-setup-inicial","Claude Code recién instalado","). Le dices en lenguaje natural:",[207,1344,1347],{"className":1345,"code":1346,"language":1219},[1217],"genera 3 variaciones de una foto cenital de masa madre sobre mesa de madera,\ncon la luz de la tarde, siguiendo el brand brain. Guárdalas en .\u002Fposts\u002F\n",[69,1348,1346],{"__ignoreMap":212},[24,1350,1351,1352,1354,1355,730,1358,1361,1362,47],{},"Claude lee tu petición. Sabe que tiene un script ",[69,1353,733],{},". Construye el comando con ",[69,1356,1357],{},"--prompt",[69,1359,1360],{},"--out",", lo corre 3 veces variando levemente el prompt, te entrega las 3 imágenes en la carpeta ",[69,1363,1364],{},"posts\u002F",[24,1366,1367],{},"Tú nunca tocas la terminal. La diferencia es de minutos a segundos.",[19,1369,1371,1378,1390],{"title":1370,"type":713},"El truco para que Claude entienda tu starter",[24,1372,1373,1374,1377],{},"Deja un ",[69,1375,1376],{},"CLAUDE.md"," corto en la raíz del starter con dos cosas:",[1379,1380,1381,1384],"ol",{},[61,1382,1383],{},"Cómo se invoca el script (1 ejemplo de cada modo).",[61,1385,1386,1387,1389],{},"Qué hace ",[69,1388,280],{}," (cuál es el tuyo) y dónde vive el cerebro.",[24,1391,1392],{},"Con eso Claude resuelve los detalles solo. Sin eso, te pregunta cada vez.",[93,1394],{},[37,1396,1398],{"id":1397},"_10-descarga-el-starter","10 · Descarga el starter",[24,1400,1401,1402,1405],{},"Te dejo el cerebro de marca demo, el wrapper de Keychain, el script con los dos modos, el inventario base de credenciales y un ",[69,1403,1404],{},"README"," con los 3 pasos para arrancar. Lo descomprimes en tu carpeta de proyectos y lo adaptas:",[19,1407,1410,1423,1426,1454],{"title":1408,"type":1409},"📦 brain-imagen-starter.zip","success",[24,1411,1412],{},[161,1413,1420],{"href":1414,"download":1415,"target":1416,"rel":1417},"\u002Fdownloads\u002Fbrain-imagen-starter.zip","brain-imagen-starter.zip","_blank",[1418,1419],"external","noopener",[30,1421,1422],{},"Descargar brain-imagen-starter.zip",[24,1424,1425],{},"Dentro vas a encontrar:",[58,1427,1428,1434,1439,1444],{},[61,1429,1430,1433],{},[69,1431,1432],{},"brand_brain.md"," (cerebro demo, marca ficticia para que veas la estructura)",[61,1435,1436,1438],{},[69,1437,733],{}," (script completo con los dos modos)",[61,1440,1441,1443],{},[69,1442,742],{}," (wrapper público parametrizado por proyecto)",[61,1445,1446,1449,1450,1453],{},[69,1447,1448],{},"09-CREDENTIALS\u002FREADME.md"," + ",[69,1451,1452],{},"_ficha-tipo.md"," (plantillas de inventario)",[24,1455,1456,1457,1459],{},"Requisitos: macOS, Python 3.10+, ",[69,1458,1187],{},". Y tu key de Gemini guardada en Keychain como se explicó en la sección 3.",[93,1461],{},[37,1463,1465],{"id":1464},"_11-lo-que-tienes-que-recordar","11 · Lo que tienes que recordar",[58,1467,1468,1477,1482,1485,1488,1491],{},[61,1469,1470,1471,1473,1474,1476],{},"El cerebro de marca vive en un ",[69,1472,71],{}," con frontmatter. Hex codes explícitos, lista de ",[69,1475,662],{},". Eso es lo que hace consistente cada imagen.",[61,1478,1479,1480,361],{},"La key vive en Keychain. La metadata vive en una ficha en ",[69,1481,354],{},[61,1483,1484],{},"El wrapper de Python lee la key solo cuando va a llamar al modelo. El valor no toca disco en ningún archivo del repo.",[61,1486,1487],{},"Modo A para texto a imagen. Modo B para foto local de referencia. Cuando la referencia es local, el camino es Gemini.",[61,1489,1490],{},"Itera el cerebro, no el prompt. Cuando un resultado no te guste, agrega una regla al cerebro y la próxima imagen ya sale distinto.",[61,1492,1493],{},"Claude Code dentro de VS Code llama el script por ti en lenguaje natural. Tú nunca escribes el comando.",[93,1495],{},[37,1497,1499],{"id":1498},"qué-viene-después","Qué viene después",[24,1501,1502],{},"Este patrón está atado a Gemini, que es lo que uso hoy. Pero la lógica (cerebro + key + wrapper + cliente) no depende del proveedor.",[19,1504,1506,1512],{"title":1505,"type":156},"Próximamente · el mismo patrón, multi-modelo vía Kie.ai",[24,1507,1508,1511],{},[30,1509,1510],{},"Cómo usar el mismo cerebro contra varios modelos."," Kie.ai te deja llamar a OpenAI Images, Flux, Stable Diffusion y otros desde una sola key. Te muestro cómo extender el script para elegir el modelo desde un flag y mantener el cerebro intacto.",[24,1513,1514],{},"Útil cuando un modelo se te queda corto en un estilo y quieres saltar a otro sin reescribir nada.",[93,1516],{},[11,1518],{"channel":13,"subtitle":1519,"title":1520,"url":16,"video-id":17},"Cerebro, Keychain, script, Claude Code en VS Code, todo en una sola sentada. Suscríbete y la próxima sale ahí primero.","Mira el flujo entero en video",[24,1522,1523,1524,1529],{},"¿El cerebro te quedó pegado pero no logras que el script corra? ¿Tu primera imagen salió rara? Escríbeme por DM en ",[161,1525,1528],{"href":1526,"rel":1527},"https:\u002F\u002Finstagram.com\u002Fsantaia.lab",[181],"@santaia.lab"," con el prompt y el resultado. Las dudas reales son material de la próxima guía.",[1531,1532,1533],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":212,"searchDepth":234,"depth":234,"links":1535},[1536,1537,1538,1539,1540,1543,1550,1553,1554,1555,1556,1557],{"id":39,"depth":234,"text":40},{"id":97,"depth":234,"text":98},{"id":151,"depth":234,"text":152},{"id":343,"depth":234,"text":344},{"id":521,"depth":234,"text":522,"children":1541},[1542],{"id":686,"depth":245,"text":687},{"id":725,"depth":234,"text":1544,"children":1545},"6 · El wrapper · keychain.py y generate_image.py",[1546,1548],{"id":739,"depth":245,"text":1547},"shared\u002Fsecrets\u002Fkeychain.py · wrapper de Keychain",{"id":922,"depth":245,"text":1549},"generate_image.py · el script CLI",{"id":1180,"depth":234,"text":1181,"children":1551},[1552],{"id":1227,"depth":245,"text":1228},{"id":1252,"depth":234,"text":1253},{"id":1330,"depth":234,"text":1331},{"id":1397,"depth":234,"text":1398},{"id":1464,"depth":234,"text":1465},{"id":1498,"depth":234,"text":1499},null,"Un cerebro de marca en markdown, tu key en Keychain y un script de Python. La terminal te devuelve imágenes que ya salen con tu paleta, tu tono y tu estilo. Texto a imagen y con foto de referencia.","md",{},"avanzado","\u002Fbiblioteca\u002Fimagenes-con-tu-marca-desde-vscode","2026-05-24",{"title":5,"description":1559},"biblioteca\u002Fimagenes-con-tu-marca-desde-vscode",[1568,1569,551,1570,1571,1572],"gemini","imagenes","keychain","vscode","claude-code","ONC0gxpHtJSzh5b-BuLJxhrDuzHxYqW1gM8fgsBuvw8",1783576708428]