Jekyll2023-12-16T02:18:57+01:00https://blog.stranianelli.com/feed.xmlStrani AnelliI'm a hobby programmer, experimenting with Construct 3, Javascript and DenoJS.Samuelesamuele@stranianelli.comReverse Engineering in Midjourney: Tracking Down the Original Style URLs2023-12-15T23:30:00+01:002023-12-15T23:30:00+01:00https://blog.stranianelli.com/reverse-engineering-midjourney-style<p>One of the most interesting features of Midjourney is the ability to create customized styles. The <code class="language-plaintext highlighter-rouge">/tune</code> function interprets the prompt and allows refining and personalizing the style of images generated by Artificial Intelligence. This way, it’s possible to maintain a stylistic consistency across different iterations. However, like any tool, it requires some practice to handle it well. A good way to start is by studying the various styles already available and trying to understand how to replicate them.</p>
<p>But what’s the problem? Well, styles are shared in this way:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Description: Flat abstract illustration.
Prompt Template: [3-5 words single focus subject], abstract --style v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft
[contributed by @Mardiray]
</code></pre></div></div>
<p>Mardiray has created several interesting styles, and this one in particular: it allows creating abstract illustrations, very suitable for illustrating posts.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/flat-gallery.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/flat-gallery.jpg" alt="flat-gallery" class="lazy" />
</picture>
<p>I tried to replicate the same style using commands like these:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/tune prompt: illustration abstract flat
/tune prompt: flat abstract
/tune prompt: solid color flat abstract
</code></pre></div></div>
<p>The problem is that I only get abstract images, and generally less beautiful ones. After a few failed attempts, I began to wonder how to understand what the original command used by Mardiray to generate the style was.</p>
<p>There are two methods for this kind of “reverse engineering”. The first, the simplest, is to use this link: <a href="ttps://cdn.kaetemi.be/dl/mj/style_dec_r6.html">Style Decoder for Midjourney (V1) — Revision 6</a>:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-01.jpg" alt="style-decoder-for-midjourney-01" class="lazy" />
</picture>
<p>After pasting the style code (in this case <code class="language-plaintext highlighter-rouge">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</code>) into the text box, I click on <code class="language-plaintext highlighter-rouge">Convert</code>:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-02.jpg" alt="style-decoder-for-midjourney-02" class="lazy" />
</picture>
<p>I get a series of useful information, but what now interests me are the first lines, with two links:</p>
<ul>
<li>Style Tuner: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a></li>
<li>Alternate Tuner: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqCauQHGT">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqCauQHGT</a></li>
</ul>
<p>Clicking on the first link, I get the original prompt, <code class="language-plaintext highlighter-rouge">House by canal</code></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-03.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-03.jpg" alt="style-decoder-for-midjourney-03" class="lazy" />
</picture>
<p>Immediately below are the generated images, with those selected highlighted, allowing Midjourney to create the customized style.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-04.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-04.jpg" alt="style-decoder-for-midjourney-04" class="lazy" />
</picture>
<p>At the bottom of the page, I find an example prompt with the created style</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-05.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/style-decoder-for-midjourney-05.jpg" alt="style-decoder-for-midjourney-05" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/imagine prompt: House by canal --style v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft
</code></pre></div></div>
<p>The second method is just as simple but doesn’t work if the style was originated from the <code class="language-plaintext highlighter-rouge">--style random</code> command.</p>
<p>To obtain the origin prompt of the style, it’s enough to replace <code class="language-plaintext highlighter-rouge"><code></code> with the style at this address:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://tuner.midjourney.com/code/<code>
</code></pre></div></div>
<p>Using the same style as an example, I get: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a>. After clicking on the address, I get a new address in the format:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://tuner.midjourney.com/<tuner>?answer=<code>
</code></pre></div></div>
<p>In my case, <a href="https://tuner.midjourney.com/kMU8tgR?answer=v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">https://tuner.midjourney.com/kMU8tgR?answer=v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a>.</p>
<p>Besides the possibility of studying the original prompts, and thus improving one’s artistic skills, being able to access the original tuner’s URL allows experimenting without having to use <code class="language-plaintext highlighter-rouge">Fast Time</code>.</p>
<p>For example, I can modify the same style to get a decidedly darker effect:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Description: Realistic dark illustration.
Prompt Template: [3-5 words single focus subject], dark --style 14yasUfsTj8AuhAwbpNP599Sykn4Rde4B36j
</code></pre></div></div>
<p>If I recreate the same images from the first example using this new style and compare the result, I get this</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/flat-dark-gallery.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-reverse-engineering-midjourney-style/flat-dark-gallery.jpg" alt="flat-dark-gallery" class="lazy" />
</picture>Samuelesamuele@stranianelli.comOne of the most interesting features of Midjourney is the ability to create customized styles. The /tune function interprets the prompt and allows refining and personalizing the style of images generated by Artificial Intelligence. This way, it’s possible to maintain a stylistic consistency across different iterations. However, like any tool, it requires some practice to handle it well. A good way to start is by studying the various styles already available and trying to understand how to replicate them.Guida Pratica al Reverse Engineering degli Stili di Midjourney2023-12-15T20:30:00+01:002023-12-15T20:30:00+01:00https://blog.stranianelli.com/midjourney-style-tuner-reverse<p>Una delle funzioni più interessanti di Midjourney è la possibilità di creare stili personalizzati. La funzione <code class="language-plaintext highlighter-rouge">/tune</code> interpreta il prompt e permette di affinare e personalizzare lo stile delle immagini generate dall’Intelligenza Artificiale. In questo modo è possibile mantenere una coerenza stilistica attraverso le diverse iterazioni. Ma come ogni strumento richiede una certa pratica per maneggiarlo bene. Un buon modo è studiare i diversi stili già disponibili e tentare di capire come replicarli.</p>
<p>Ma qual è il problema? Beh, che gli stili vengono condivisi in questo modo:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Description: Flat abstract illustration.
Prompt Template: [3-5 words single focus subject], abstract --style v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft
[contributed by @Mardiray]
</code></pre></div></div>
<p>Mardiray ha creato diversi stili interessanti, e questo in particolar modo: permette di creare illustrazioni astratte, molto adatte per illustrare post.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/flat-gallery.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/flat-gallery.jpg" alt="flat-gallery" class="lazy" />
</picture>
<p>Ho provato a replicare lo stesso stile usando comandi simili a questi:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/tune prompt: illustration abstract flat
/tune prompt: flat abstract
/tune prompt: solid color flat abstract
</code></pre></div></div>
<p>Il problema è che ottengo solamente immagini astratte, e in generale meno belle. Dopo un po’ di tentativi andati a vuoto ho cominciato a chiedermi come capire quale fosse il comando originale utilizzato da Mardiray per generare lo stile.</p>
<p>Ci sono due metodi per fare questa specie di “reverse engineering”. Il primo, il più semplice, è usare questo link: <a href="https://cdn.kaetemi.be/dl/mj/style_dec_r6.html">Style Decoder for Midjourney (V1) — Revision 6</a>:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-01.jpg" alt="style-decoder-for-midjourney-01" class="lazy" />
</picture>
<p>Dopo aver incollato il codice dello stile (in questo caso <code class="language-plaintext highlighter-rouge">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</code>) nella casella di testo, clicco su <code class="language-plaintext highlighter-rouge">Convert</code>:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-02.jpg" alt="style-decoder-for-midjourney-02" class="lazy" />
</picture>
<p>Ottengo una serie di informazioni utili, ma quelle che adesso mi interessano sono le prime righe, con due link:</p>
<ul>
<li>Style Tuner: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a></li>
<li>Alternate Tuner: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqCauQHGT">v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqCauQHGT</a></li>
</ul>
<p>Cliccando sul primo link ottengo il prompt originale, <code class="language-plaintext highlighter-rouge">House by canal</code></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-03.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-03.jpg" alt="style-decoder-for-midjourney-03" class="lazy" />
</picture>
<p>Subito sotto ci sono le immagini generate, con evidenziate quelle selezionate e che permettono a Midjourney di creare lo stile personalizzato.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-04.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-04.jpg" alt="style-decoder-for-midjourney-04" class="lazy" />
</picture>
<p>A fondo pagina trovo un prompt di esempio con lo stile creato</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-05.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/style-decoder-for-midjourney-05.jpg" alt="style-decoder-for-midjourney-05" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/imagine prompt: House by canal --style v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft
</code></pre></div></div>
<p>Il secondo metodo è altrettanto semplice ma non funziona se lo stile è stato originato dal comando <code class="language-plaintext highlighter-rouge">--style random</code>.</p>
<p>Per ottenere il prompt di origine dello stile è sufficiente sostituire <code class="language-plaintext highlighter-rouge"><code></code> con lo stile a questo indirizzo:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://tuner.midjourney.com/code/<code>
</code></pre></div></div>
<p>Usando sempre lo stesso stile come esempio, ottengo: <a href="https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">https://tuner.midjourney.com/code/v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a>. Dopo aver cliccato sull’indirizzo, ottengo un nuovo indirizzo nel formato:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://tuner.midjourney.com/<tuner>?answer=<code>
</code></pre></div></div>
<p>Nel mio caso, <a href="https://tuner.midjourney.com/kMU8tgR?answer=v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft">https://tuner.midjourney.com/kMU8tgR?answer=v6k9dkS9FT4SPJwK0jc2sn7vURzlhorZqDL5jlft</a></p>
<p>Oltre alla possibilità di studiare i prompt originali, e quindi migliorare le proprie capacità artistiche, poter accedere al’URL del tuner originale permette di sperimentare senza dover usare <code class="language-plaintext highlighter-rouge">Fast Time</code>.</p>
<p>Per esempio, posso modificare lo stesso stile per ottenere un effetto decisamente più dark:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Description: Realistic dark illustration.
Prompt Template: [3-5 words single focus subject], dark --style 14yasUfsTj8AuhAwbpNP599Sykn4Rde4B36j
</code></pre></div></div>
<p>Se ricreo le stesse immagini del primo esempio usando questo nuovo stile e confronto il risultato, ottengo questo</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/flat-dark-gallery.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-15-midjourney-style-tuner-reverse/flat-dark-gallery.jpg" alt="flat-dark-gallery" class="lazy" />
</picture>Samuelesamuele@stranianelli.comUna delle funzioni più interessanti di Midjourney è la possibilità di creare stili personalizzati. La funzione /tune interpreta il prompt e permette di affinare e personalizzare lo stile delle immagini generate dall’Intelligenza Artificiale. In questo modo è possibile mantenere una coerenza stilistica attraverso le diverse iterazioni. Ma come ogni strumento richiede una certa pratica per maneggiarlo bene. Un buon modo è studiare i diversi stili già disponibili e tentare di capire come replicarli.Creare Prompts per Midjourney con ChatGPT2023-12-11T20:20:00+01:002023-12-11T20:20:00+01:00https://blog.stranianelli.com/chatgpt-prompt-generator-midjourney-it<p>Oggi Medium mi ha consigliato un post di <a href="https://tristwolff.medium.com/">Tristan Wolff</a> su come usare <a href="https://medium.com/the-generator/turn-chatgpt-into-a-midjourney-prompt-generator-a-step-by-step-guide-d447479f8a48">ChatGPT per creare prompt per Midjourney</a>. È stata una lettura interessante e mi ha spinto ad esplorare questa possibilità a mia volta. Dopo aver giocato un pochetto con ChatGPT ho avuto il mio momento “Eureka!”: posso usare questo motore linguistico allo stesso modo di un qualsiasi altro linguaggio di programmazione.</p>
<p>Probabilmente è una cosa oramai banale. In fin dei conti ChatGPT è in circolazione da un po’ di tempo, e molti più perspicaci di me hanno avuto modo di giocarci. Ma, fino ad oggi, non avevo mai davvero avuto la necessità di usarlo per qualcosa di non convenzionale. Ma partiamo dall’inizio.</p>
<p>Per prima cosa, ChatGPT non conosce Midjourney. Non ancora per lo meno. Quindi qualsiasi comando deve essere per forza di cosa in una forma algoritmica. In altre parole, istruzioni. Righe di codice.</p>
<p>Comincio con l’introdurre l’argomento di cui parlerò:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello, today we're talking about Midjourney.
</code></pre></div></div>
<p>Salutare è buona educazione. Passo poi a spiegare cos’è Midjourney:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Midjourney is an Artificial Intelligence capable of generating images based on textual instructions.
</code></pre></div></div>
<p>In questo modo ChatGPT ha un contesto su cui lavorare. Adesso è il momento di dichiarare il risultato che voglio ottenere:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The simplest prompt is structured as follows:
/imagine prompt: PREFIX, SCENE, SUFFIX, IN THE STYLE OF, --ar 3:2
PREFIX indicates the style and material with which the image is created.
SCENE indicates the content of the image.
SUFFIX modulates PREFIX and SCENE.
IN THE STYLE OF indicates the name of an artist or artistic movement.
--ar 3:2 indicates the aspect ratio of the image (width to height).
</code></pre></div></div>
<p>In pratica, sto dicendo a ChatGPT quale risultato voglio ottenere. Ma aggiungo una possibilità:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IN THE STYLE OF is optional. If you don't use it, don't write "in the style of"
</code></pre></div></div>
<p>Poiché ChatGPT tende a essere prolisso, aggiungo un vincolo:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The prompt should be shorter than 60 words.
</code></pre></div></div>
<p>E, per puro gusto estetico, voglio che:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The prompt should be in lowercase.
I want the prompts like a numbered list.
</code></pre></div></div>
<p>Dopo aver spiegato a ChatGPT cosa voglio ottenere, è il momento di semplificare il mio modo per chiederglielo. Comincio con il dichiarare una funzione che restituisca un solo prompt:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>To request a prompt, I'll use the phrase:
MJ: THEME
THEME: indicates the idea I want to convey through the image.
</code></pre></div></div>
<p>La funzione <code class="language-plaintext highlighter-rouge">MJ</code> (che sta ovviamente per <code class="language-plaintext highlighter-rouge">Midjourney</code>) richiede un solo parametro, <code class="language-plaintext highlighter-rouge">THEME</code>.</p>
<p>Aggiungo poi una seconda funzione per creare più prompt con un’unica richiesta:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>To request more prompts, I'll use the phrase:
NxMJ: THEME
THEME: indicates the idea I want to convey through the image.
N: indicates the number of prompts I want
</code></pre></div></div>
<p>La funzione <code class="language-plaintext highlighter-rouge">NxMJ</code> richiede due parametri: <code class="language-plaintext highlighter-rouge">THEME</code> e <code class="language-plaintext highlighter-rouge">N</code></p>
<p>Per finire registro questo codice nella chat di ChatGPT:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Is everything clear?
</code></pre></div></div>
<p>Mettendo tutto assieme, il prompt è:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello, today we're talking about Midjourney. Midjourney is an Artificial Intelligence capable of generating images based on textual instructions. The simplest prompt is structured as follows:
/imagine prompt: PREFIX, SCENE, SUFFIX, IN THE STYLE OF, --ar 3:2
PREFIX indicates the style and material with which the image is created.
SCENE indicates the content of the image.
SUFFIX modulates PREFIX and SCENE.
IN THE STYLE OF indicates the name of an artist or artistic movement.
--ar 3:2 indicates the aspect ratio of the image (width to height).
IN THE STYLE OF is optional. If you don't use it, don't write "in the style of"
The prompt should be shorter than 60 words.
The prompt should be in lowercase.
I want the prompts like a numbered list.
To request a prompt, I'll use the phrase:
MJ: THEME
THEME: indicates the idea I want to convey through the image.
To request more prompts, I'll use the phrase:
NxMJ: THEME
THEME: indicates the idea I want to convey through the image.
N: indicates the number of prompts I want
Is everything clear?
</code></pre></div></div>
<h3 id="mettiamo-alla-prova-chatgpt">Mettiamo alla Prova ChatGPT</h3>
<p>È il momento di fare un po’ di test. Comincio con il chiedere un solo prompt:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
1xMJ: Love in Venice
ChatGPT:
1. /imagine prompt: romantic gondola ride, under moonlight, with whispers of passion, --ar 3:2
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/prompt-01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/prompt-01.jpg" alt="1xMJ: Love in Venice" class="lazy" />
</picture>
<p>Mettiamo subito alla prova Midjourney con questo prompt e vediamo cosa tira fuori:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-01.jpg" alt="romantic gondola ride, under moonlight, with whispers of passion" class="lazy" />
</picture>
<p>Bene, adesso proviamo a chiedere più prompt in una volta sola:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
10xMJ: Love in Venice
ChatGPT:
1. /imagine prompt: romantic gondola ride, under moonlight, with whispers of passion, --ar 3:2
2. /imagine prompt: aged stone bridge, shared gelato on a canal, stolen kisses, in the style of Monet, --ar 3:2
3. /imagine prompt: vibrant masquerade, serenaded by a violin, mysterious allure, --ar 3:2
4. /imagine prompt: hidden courtyard, Venetian masks, secret rendezvous, --ar 3:2
5. /imagine prompt: candlelit dinner by the Grand Canal, reflection of love in the water, --ar 3:2
6. /imagine prompt: passionate tango on a cobblestone street, surrounded by ancient architecture, --ar 3:2
7. /imagine prompt: love letters exchanged on a historic Venetian balcony, overlooking the city, --ar 3:2
8. /imagine prompt: enchanting carnival proposal, fireworks in the night sky, --ar 3:2
9. /imagine prompt: morning sunrise over the canals, lovebirds on a quiet bridge, --ar 3:2
10. /imagine prompt: a Venetian wedding procession, joyous celebration in the streets, --ar 3:2
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/prompt-02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/prompt-02.jpg" alt="10xMJ: Love in Venice" class="lazy" />
</picture>
<p>Direi che ci siamo. ChatGPT propone diverse soluzioni riguardo al tema che gli ho proposto. Interessante come non usi spesso “IN THE STYLE OF MONET”. Proviamo a usare il prompt 2</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-02.jpg" alt="aged stone bridge, shared gelato on a canal, venice, stolen kisses, in the style of Monet, --ar 3:2" class="lazy" />
</picture>
<p>Ok, qui c’è qualche problema su dove mettere la coppia di innamorati, se sopra o sotto il ponte.</p>
<h3 id="chiediamo-a-chatgpt-di-personalizzare-il-risultato">Chiediamo a ChatGPT di personalizzare il risultato</h3>
<p>Far fare tutto a ChatGPT permette di velocizzare il processo di creazione dei prompt ma ci fa perdere il controllo sul risultato finale. Possiamo però usare lo stesso comando per creare prompt per degli usi particolari.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
4xMJ: Love in Venice
For a black and white newspaper
ChatGPT:
1. /imagine prompt: timeless embrace on a Venetian bridge, shadows dancing in black and white, --ar 4:5
2. /imagine prompt: candid moment of love in a narrow alley, vintage attire, captured in grayscale, --ar 4:5
3. /imagine prompt: silhouette of a romantic gondola ride, under the moonlight, minimalist black and white, --ar 4:5
4. /imagine prompt: classic Venetian masks at a masquerade, grayscale elegance, hinting at mystery, --ar 4:5
</code></pre></div></div>
<p>Interessante come in questo caso ChatGPT abbia deciso di cambiare le dimensioni delle immagini.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-03.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-03.jpg" alt="timeless embrace on a Venetian bridge, shadows dancing in black and white, --ar 4:5" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
4xMJ: Love in Venice
With Donald Duck
For a Disney comics
ChatGPT:
1. /imagine prompt: Donald Duck navigating a gondola in the Venetian canals, comical mishaps and love-struck expressions, --ar 16:9
2. /imagine prompt: Donald and Daisy in Venetian carnival attire, participating in lively antics during the festivities, --ar 16:9
3. /imagine prompt: Donald proposing to Daisy on a wobbly Venetian bridge, humorous and heartfelt, --ar 16:9
4. /imagine prompt: Donald, Daisy, and friends enjoying a romantic evening in a Venetian square, filled with Disney-style love and laughter, --ar 16:9
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-04.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-04.jpg" alt="Donald, Daisy, and friends enjoying a romantic evening in a Venetian square, filled with Disney-style love and laughter, --ar 16:9" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
4xMJ: Love in Venice
For a sculture project
ChatGPT:
1. /imagine prompt: Sculpture of intertwined lovers on a Venetian bridge, capturing the essence of eternal love, --ar 1:1
2. /imagine prompt: Abstract sculpture symbolizing the dance of passion in a Venetian square, harmonizing forms in stone, --ar 1:1
3. /imagine prompt: Sculpture depicting a romantic gondola ride frozen in time, evoking movement and emotion in marble, --ar 1:1
4. /imagine prompt: Sculpture ensemble portraying a Venetian masquerade, masks and figures elegantly carved in stone, --ar 1:1
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-05.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-05.jpg" alt="Sculpture of intertwined lovers on a Venetian bridge, capturing the essence of eternal love, --ar 1:1" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Me:
4xMJ: Love in Venice
But with only solid color (black, white, red, white)
Flattened image
For magazine illustration
ChatGPT:
1. /imagine prompt: Solid red silhouette of a romantic gondola ride in Venice, capturing the essence of love, --ar 4:5
2. /imagine prompt: Black and white illustration of a Venetian bridge with a couple in an embrace, timeless and elegant, --ar 4:5
3. /imagine prompt: White on red illustration of a Venetian masquerade, capturing the mystery and allure of love, --ar 4:5
4. /imagine prompt: Red and white minimalist depiction of a candlelit dinner by the Grand Canal, subtle and romantic, --ar 4:5
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-06.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-06.jpg" alt="Solid red flat abstract illustration of a romantic gondola ride in Venice, capturing the essence of love, --ar 4:5" class="lazy" />
</picture>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ME:
4xMJ: Love in Venice
For a ghotic vampire romance
ChatGPT:
1. /imagine prompt: Gothic vampire couple in a Venetian cemetery, eternal love under a blood-red moon, --ar 3:4
2. /imagine prompt: Vampire masquerade in a darkened Venetian palace, shadows and seduction, --ar 3:4
3. /imagine prompt: Brooding vampire overlooking the canals, haunted by memories of love, black and white with a touch of crimson, --ar 3:4
4. /imagine prompt: Veiled vampire bride in a decaying Venetian mansion, a ghostly love story in shades of deep violet, --ar 3:4
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-07.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-07.jpg" alt="Gothic vampire couple in a Venetian cemetery, eternal love under a blood-red moon, --ar 3:4" class="lazy" />
</picture>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ME:
4xMJ: Love in Venice
For a ghotic vampire romance
ChatGPT:
1. /imagine prompt: Futuristic cityscape with floating gondolas, a love story transcending time in a sci-fi Venice, --ar 16:9
2. /imagine prompt: Alien lovers on a technologically advanced Venetian bridge, a portal to a romantic sci-fi realm, --ar 16:9
3. /imagine prompt: Cyborgs in a cyberpunk masquerade, mysterious and alluring, set against a futuristic Venetian backdrop, --ar 16:9
4. /imagine prompt: Virtual reality depiction of a love connection in a Venetian simulation, merging sci-fi and romance, --ar 16:9
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-08.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-11-chatgpt-prompt-generator-midjourney-it/image-08.jpg" alt="Alien lovers on a technologically advanced Venetian bridge, a portal to a romantic sci-fi realm, --ar 16:9" class="lazy" />
</picture>Samuelesamuele@stranianelli.comOggi Medium mi ha consigliato un post di Tristan Wolff su come usare ChatGPT per creare prompt per Midjourney. È stata una lettura interessante e mi ha spinto ad esplorare questa possibilità a mia volta. Dopo aver giocato un pochetto con ChatGPT ho avuto il mio momento “Eureka!”: posso usare questo motore linguistico allo stesso modo di un qualsiasi altro linguaggio di programmazione.Using Tailwind With Svelte and Construct 32023-12-10T22:45:00+01:002023-12-10T22:45:00+01:00https://blog.stranianelli.com/using-tailwind-with-svelte<p>After resuming playing with Svelte, TypeScript, and Construct 3, it’s time to add <a href="https://tailwindcss.com/">Tailwind CSS</a> to my test project. I’ve previously covered this topic in 2021 (<a href="https://blog.stranianelli.com/tailwind-and-svelte/">Tailwind CSS & Svelte</a>), but a few years have passed since then. There’s a LogRocket tutorial (<a href="https://blog.logrocket.com/how-to-use-tailwind-css-svelte/">How to use Tailwind CSS with Svelte</a>) updated in July 2023, but in my opinion, it doesn’t present the best solution. Consequently, here are my notes on how to add Tailwind CSS to a Svelte project.</p>
<p>I resume the project from a few days ago (<a href="https://blog.stranianelli.com/using-typescript-and-svelte-in-construct/">this one</a>) and navigate to the folder with the Svelte code using the terminal. I enter the following command in the terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-D</span> tailwindcss@latest postcss@latest
</code></pre></div></div>
<p>This command adds Tailwind and <a href="https://postcss.org/">PostCSS</a> packages to Svelte. Then I add <a href="https://www.npmjs.com/package/autoprefixer">Autoprefixer</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-D</span> autoprefixer@latest
</code></pre></div></div>
<p>And finally, I can initialize Tailwind with the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx tailwindcss init <span class="nt">-p</span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/npx-tailwind-init.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/npx-tailwind-init.jpg" alt="npx-tailwind-init" class="lazy" />
</picture>
<p>This command creates two files:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">tailwind.config.js</code></li>
<li><code class="language-plaintext highlighter-rouge">postcss.config.js</code></li>
</ul>
<p>I start by modifying <code class="language-plaintext highlighter-rouge">tailwind.config.js</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** @type {import('tailwindcss').Config} */</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">{</span>
<span class="na">content</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">theme</span><span class="p">:</span> <span class="p">{</span>
<span class="na">extend</span><span class="p">:</span> <span class="p">{},</span>
<span class="p">},</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">content</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">./index.html</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">./src/**/*.{svelte,js,ts}</span><span class="dl">"</span><span class="p">],</span> <span class="c1">//for unused css</span>
<span class="p">};</span>
</code></pre></div></div>
<p>I add some elements to <code class="language-plaintext highlighter-rouge">content</code> to remove unused CSS styles from the project.</p>
<p>I also modify the <code class="language-plaintext highlighter-rouge">postcss.config.js</code> file:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">tailwind</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">tailwindcss</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">tailwindConfig</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./tailwind.config.js</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">autoprefixer</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">autoprefixer</span><span class="dl">"</span><span class="p">;</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">{</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">[</span><span class="nx">tailwind</span><span class="p">(</span><span class="nx">tailwindConfig</span><span class="p">),</span> <span class="nx">autoprefixer</span><span class="p">],</span>
<span class="p">};</span>
</code></pre></div></div>
<p>I have two ways to allow Svelte to use Tailwind styles. The first is to create a <code class="language-plaintext highlighter-rouge">TailwindCSS.svelte</code> component:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><style></span>
<span class="k">@tailwind</span> <span class="n">base</span><span class="p">;</span>
<span class="k">@tailwind</span> <span class="n">components</span><span class="p">;</span>
<span class="k">@tailwind</span> <span class="n">utilities</span><span class="p">;</span>
<span class="nt"></style></span>
</code></pre></div></div>
<p>And import it into <code class="language-plaintext highlighter-rouge">App.svelte</code>:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script></span>
<span class="k">import</span> <span class="nx">TailwindCss</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./lib/TailwindCSS.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="nt"></script></span>
<span class="nt"><TailwindCss</span> <span class="nt">/></span>
</code></pre></div></div>
<p>However, while effective, this is not my preferred method. I prefer creating a separate file and importing it directly as a stylesheet. To do this, I create the <code class="language-plaintext highlighter-rouge">tailwind.pcss</code> file (I save it in the <code class="language-plaintext highlighter-rouge">css</code> folder for convenience):</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@import</span> <span class="s1">"tailwindcss/base"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s1">"tailwindcss/components"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s1">"tailwindcss/utilities"</span><span class="p">;</span>
</code></pre></div></div>
<p>Then I import the file in <code class="language-plaintext highlighter-rouge">App.svelte</code>:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script </span><span class="na">lang=</span><span class="s">"ts"</span><span class="nt">></span>
<span class="k">import</span> <span class="dl">"</span><span class="s2">./css/tailwind.pcss</span><span class="dl">"</span><span class="p">;</span>
<span class="nt"></script></span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/svelte-app-and-tailwind.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/svelte-app-and-tailwind.jpg" alt="svelte-app-and-tailwind" class="lazy" />
</picture>
<p>No need to import anything into the various components. I can add styles directly in the component</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/counter.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte/counter.jpg" alt="counter" class="lazy" />
</picture>
<p>To preview the page, I use the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run dev
</code></pre></div></div>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/preview.gif" alt="c3 gif" /></p>
<p>And to obtain compiled files, I use the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<p>I can also delete the <code class="language-plaintext highlighter-rouge">app.css</code> file and remove the reference from <code class="language-plaintext highlighter-rouge">main.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">app</span><span class="dl">"</span><span class="p">),</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>Samuelesamuele@stranianelli.comAfter resuming playing with Svelte, TypeScript, and Construct 3, it’s time to add Tailwind CSS to my test project. I’ve previously covered this topic in 2021 (Tailwind CSS & Svelte), but a few years have passed since then. There’s a LogRocket tutorial (How to use Tailwind CSS with Svelte) updated in July 2023, but in my opinion, it doesn’t present the best solution. Consequently, here are my notes on how to add Tailwind CSS to a Svelte project.Come Aggiungere e Usare Tailwind con Svelte e Construct 32023-12-10T00:20:00+01:002023-12-10T00:20:00+01:00https://blog.stranianelli.com/using-tailwind-with-svelte-it<p>Dopo aver ripreso a giocare con Svelte, TypeScript e Construct 3 è arrivato il momento di aggiungere al mio progetto di test anche <a href="https://tailwindcss.com/">Tailwind CSS</a>. È un argomento che ho già affrontato nel 2021 (<a href="https://blog.stranianelli.com/tailwind-and-svelte/">Tailwind CSS & Svelte</a>) ma sono passati, per l’appunto, un po’ di anni. C’è un tutorial di LogRocket (<a href="https://blog.logrocket.com/how-to-use-tailwind-css-svelte/">How to use Tailwind CSS with Svelte</a>) aggiornato a Luglio 2023 ma non presenta, a mio avviso, la soluzione migliore. Di conseguenza, ecco qui i miei appunti su come aggiungere Tailwind CSS a un progetto Svelte.</p>
<p>Riprendo il progetto del post di qualche giorno fa (<a href="https://blog.stranianelli.com/using-typescript-and-svelte-in-construct/">questo</a>) e mi porto con il terminale nella cartella con il codice di Svelte. Inserisco a terminale il seguente comando:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-D</span> tailwindcss@latest postcss@latest
</code></pre></div></div>
<p>In questo modo aggiungo a Svelte i pacchetti di Tailwind e <a href="https://postcss.org/">PostCSS</a>. Poi aggiungo <a href="https://www.npmjs.com/package/autoprefixer">Autoprefixer</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-D</span> autoprefixer@latest
</code></pre></div></div>
<p>E finalmente posso inizializzare Tailwind con il comando:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx tailwindcss init <span class="nt">-p</span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/npx-tailwind-init.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/npx-tailwind-init.jpg" alt="npx-tailwind-init" class="lazy" />
</picture>
<p>Questo comando crea due file:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">tailwind.config.js</code></li>
<li><code class="language-plaintext highlighter-rouge">postcss.config.js</code></li>
</ul>
<p>Comincio con il modificare <code class="language-plaintext highlighter-rouge">tailwind.config.js</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** @type {import('tailwindcss').Config} */</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">{</span>
<span class="na">content</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">theme</span><span class="p">:</span> <span class="p">{</span>
<span class="na">extend</span><span class="p">:</span> <span class="p">{},</span>
<span class="p">},</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">content</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">./index.html</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">./src/**/*.{svelte,js,ts}</span><span class="dl">"</span><span class="p">],</span> <span class="c1">//for unused css</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Aggiungo alcuni elementi a <code class="language-plaintext highlighter-rouge">content</code> per permettere a Tailwind di rimuovere gli stili CSS non usati dal progetto.</p>
<p>Modifico anche il file <code class="language-plaintext highlighter-rouge">postcss.config.js</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">tailwind</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">tailwindcss</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">tailwindConfig</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./tailwind.config.js</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">autoprefixer</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">autoprefixer</span><span class="dl">"</span><span class="p">;</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">{</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">[</span><span class="nx">tailwind</span><span class="p">(</span><span class="nx">tailwindConfig</span><span class="p">),</span> <span class="nx">autoprefixer</span><span class="p">],</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Ho due modi per permettere a Svelte di usare gli stili di Tailwind. Il primo è di creare un componente <code class="language-plaintext highlighter-rouge">TailwindCSS.svelte</code>:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><style></span>
<span class="k">@tailwind</span> <span class="n">base</span><span class="p">;</span>
<span class="k">@tailwind</span> <span class="n">components</span><span class="p">;</span>
<span class="k">@tailwind</span> <span class="n">utilities</span><span class="p">;</span>
<span class="nt"></style></span>
</code></pre></div></div>
<p>e di importarlo in <code class="language-plaintext highlighter-rouge">App.svelte</code>:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script></span>
<span class="k">import</span> <span class="nx">TailwindCss</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./lib/TailwindCSS.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="nt"></script></span>
<span class="nt"><TailwindCss</span> <span class="nt">/></span>
</code></pre></div></div>
<p>Ma per quanto efficace non è il mio metodo preferito. Preferisco creare un file separato e importarlo direttamente come foglio di stile. Per farlo creo il file <code class="language-plaintext highlighter-rouge">tailwind.pcss</code> (per comodità lo salvo nella cartella <code class="language-plaintext highlighter-rouge">css</code>).</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@import</span> <span class="s1">"tailwindcss/base"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s1">"tailwindcss/components"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s1">"tailwindcss/utilities"</span><span class="p">;</span>
</code></pre></div></div>
<p>Poi importo il file in <code class="language-plaintext highlighter-rouge">App.svelte</code>:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script </span><span class="na">lang=</span><span class="s">"ts"</span><span class="nt">></span>
<span class="k">import</span> <span class="dl">"</span><span class="s2">./css/tailwind.pcss</span><span class="dl">"</span><span class="p">;</span>
<span class="nt"></script></span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/svelte-app-and-tailwind.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/svelte-app-and-tailwind.jpg" alt="svelte-app-and-tailwind" class="lazy" />
</picture>
<p>Non è necessario importare nulla nei vari componenti. Posso aggiungere gli stili direttamente nel componente:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/counter.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/counter.jpg" alt="counter" class="lazy" />
</picture>
<p>Per vedere l’anteprima della pagina uso il comando</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run dev
</code></pre></div></div>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-10-using-tailwind-with-svelte-it/preview.gif" alt="c3 gif" /></p>
<p>Invece per ottenere i file compilati uso il comando:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<p>Posso anche eliminare il file <code class="language-plaintext highlighter-rouge">app.css</code> e togliere il riferimento da <code class="language-plaintext highlighter-rouge">main.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">app</span><span class="dl">"</span><span class="p">),</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>Samuelesamuele@stranianelli.comDopo aver ripreso a giocare con Svelte, TypeScript e Construct 3 è arrivato il momento di aggiungere al mio progetto di test anche Tailwind CSS. È un argomento che ho già affrontato nel 2021 (Tailwind CSS & Svelte) ma sono passati, per l’appunto, un po’ di anni. C’è un tutorial di LogRocket (How to use Tailwind CSS with Svelte) aggiornato a Luglio 2023 ma non presenta, a mio avviso, la soluzione migliore. Di conseguenza, ecco qui i miei appunti su come aggiungere Tailwind CSS a un progetto Svelte.Achieving 100% Child Div Height Without Specifying Parent’s2023-12-08T23:30:00+01:002023-12-08T23:30:00+01:00https://blog.stranianelli.com/achieving-100-percent-child-div-height-without-specifying-parents<p>A brief note to remind my future self how to use CSS to make an element occupy all available vertical space without having (or being able) to set the size of the parent element.In other words, given an element <code class="language-plaintext highlighter-rouge">main</code> with unknown dimensions, make the <code class="language-plaintext highlighter-rouge">div</code> height 100% of <code class="language-plaintext highlighter-rouge">main</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-08-achieving-100-percent-child-div-height-without-specifying-parents/schema.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-08-achieving-100-percent-child-div-height-without-specifying-parents/schema.jpg" alt="error" class="lazy" />
</picture>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">main</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span>
<span class="c">/* align-content: center;
justify-content: center; */</span>
<span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span>
<span class="nl">align-items</span><span class="p">:</span> <span class="n">stretch</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">div</span> <span class="p">{</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This is the expected outcome:</p>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-08-achieving-100-percent-child-div-height-without-specifying-parents/c3.gif" alt="c3 gif" /></p>
<p>And these are the styles used (with a touch of TailwindCSS):</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">main</span> <span class="p">{</span>
<span class="nl">font-family</span><span class="p">:</span> <span class="n">Inter</span><span class="p">,</span> <span class="n">system-ui</span><span class="p">,</span> <span class="n">Avenir</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span>
<span class="nl">align-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span>
<span class="nl">align-items</span><span class="p">:</span> <span class="n">stretch</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.card</span> <span class="p">{</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">2rem</span><span class="p">;</span>
<span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">left</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">2em</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">button</span> <span class="p">{</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="err">@apply</span> <span class="err">border</span> <span class="err">rounded-full</span> <span class="err">border-indigo-600</span> <span class="err">relative</span> <span class="err">items-center</span> <span class="err">justify-center</span> <span class="err">overflow-hidden</span> <span class="err">bg-slate-100</span> <span class="err">text-lg</span> <span class="err">font-medium</span> <span class="err">text-indigo-900</span> <span class="err">shadow;</span>
<span class="p">}</span>
<span class="nt">button</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="err">@apply</span> <span class="err">border-amber-600</span> <span class="err">delay-150</span> <span class="err">duration-500</span> <span class="err">bg-amber-200</span> <span class="err">text-amber-800</span> <span class="err">ease-in-out;</span>
<span class="p">}</span>
<span class="nt">button</span><span class="nd">:active</span> <span class="p">{</span>
<span class="err">@apply</span> <span class="err">shadow</span> <span class="err">animate-ping;</span>
<span class="p">}</span>
</code></pre></div></div>Samuelesamuele@stranianelli.comA brief note to remind my future self how to use CSS to make an element occupy all available vertical space without having (or being able) to set the size of the parent element.In other words, given an element main with unknown dimensions, make the div height 100% of main.Using TypeScript and Svelte in Construct 32023-12-04T11:00:00+01:002023-12-04T11:00:00+01:00https://blog.stranianelli.com/using-typescript-and-svelte-in-construct<p>The latest version of Construct 3 introduces an interesting feature: the ability to use TypeScript. Ashley wrote a comprehensive guide on the various steps to follow (you can find it <a href="https://www.construct.net/en/tutorials/using-typescript-construct-3003">here</a>). Building upon this, I want to add some notes on how to integrate Svelte into a Construct project.</p>
<p>These notes are divided into two parts. In the first part, I’ll summarize the main steps to use TypeScript within C3. It’s a condensed version of Ashley’s guide. In the second part, I’ll focus on using Svelte, reproducing the simplest example:</p>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/simple-click-button.gif" alt="Simple Click Button gif" /></p>
<h2 id="typescript--construct">TypeScript & Construct</h2>
<h3 id="configure-your-computer">Configure Your Computer</h3>
<p>The first thing to do is make sure you have <a href="https://nodejs.org/">Node.js</a> installed on your computer. Secondly install TypeScript from the terminal using the command <code class="language-plaintext highlighter-rouge">npm install -g typescript</code>. You can check the installed version using the command <code class="language-plaintext highlighter-rouge">tsc --version</code>.</p>
<p>Ashley also mentions this potential error:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/error.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/error.jpg" alt="error" class="lazy" />
</picture>
<h3 id="create-the-project">Create the Project</h3>
<p>After setting up your computer, you can create a project in Construct. Save the project “As Folder” using the command <code class="language-plaintext highlighter-rouge">Menu ► Project ► Save as ► Save as project folder...</code></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/save-as-project-folder.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/save-as-project-folder.jpg" alt="Menu ► Project ► Save as ► Save as project folder..." class="lazy" />
</picture>
<p>The next step is right-click on <code class="language-plaintext highlighter-rouge">Scripts</code> and choose <code class="language-plaintext highlighter-rouge">TypeScript ► Set up TypeScript</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/set-up-typescript.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/set-up-typescript.jpg" alt="TypeScript ► Set up TypeScript" class="lazy" />
</picture>
<p>Since you’ll be working on files on your PC but testing changes through Construct, it’s a good idea to enable the “<em>Auto reload all on preview</em>” option.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/auto-reload-all-on-preview.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/auto-reload-all-on-preview.jpg" alt="Auto reload all on preview" class="lazy" />
</picture>
<p>Now you can open the project with your preferred text editor. In my case, I use Visual Studio Code.</p>
<p>In VS Code, I use the key combination <code class="language-plaintext highlighter-rouge">Ctrl + Shift + B</code> to select <code class="language-plaintext highlighter-rouge">tsc: watch</code> and enable the automatic compilation of <code class="language-plaintext highlighter-rouge">.ts</code> files into <code class="language-plaintext highlighter-rouge">.js</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/ts-watch.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/ts-watch.jpg" alt="tsc: watch" class="lazy" />
</picture>
<h3 id="utilities">Utilities</h3>
<p>C3 sets up the project with all the essential files, but you can add some files to simplify your future workflow.</p>
<p>I create the file <code class="language-plaintext highlighter-rouge">scripts/definitions/customGlobal.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="p">{};</span>
<span class="kr">declare</span> <span class="nb">global</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">g_runtime</span><span class="p">:</span> <span class="nx">IRuntime</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/custom-global.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/custom-global.jpg" alt="scripts/definitions/customGlobal.ts" class="lazy" />
</picture>
<p>This allows me to customize <code class="language-plaintext highlighter-rouge">globalThis</code>.</p>
<p>Then I add the file <code class="language-plaintext highlighter-rouge">scripts/definitions/defs.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kr">interface</span> <span class="nx">Globals</span> <span class="p">{}</span>
</code></pre></div></div>
<p>This interface will be useful for adding global variables to the application. To use it, I create the file <code class="language-plaintext highlighter-rouge">scripts/globals.ts</code></p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="kd">type</span> <span class="p">{</span> <span class="nx">Globals</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./definitions/defs</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Globals</span><span class="p">:</span> <span class="nx">Globals</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">Globals</span><span class="p">;</span>
</code></pre></div></div>
<p>Now it’s time to organize the files generated by Construct. I open <code class="language-plaintext highlighter-rouge">scripts/main.ts</code>, delete all the content, and write:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">runOnStartup</span><span class="p">(</span><span class="k">async</span> <span class="p">(</span><span class="nx">runtime</span><span class="p">:</span> <span class="nx">IRuntime</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">globalThis</span><span class="p">.</span><span class="nx">g_runtime</span> <span class="o">=</span> <span class="nx">runtime</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div></div>
<p>This code allows me to invoke the runtime directly from C3.</p>
<p>Finally, I modify the file <code class="language-plaintext highlighter-rouge">importsForEvents.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">Globals</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./globals.js</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div></div>
<p>This file allows Construct’s Event Sheets to communicate directly with the code generated from TypeScript.</p>
<h2 id="svelte--construct">Svelte & Construct</h2>
<h3 id="set-up-svelte">Set Up Svelte</h3>
<p>So far, we’ve covered configuring C3 and TypeScript. Now it’s time to add <a href="https://svelte.dev/">Svelte</a>.</p>
<p>Remember the purpose of this tutorial: creating a button that counts clicks. In other words, replicating a basic example.</p>
<p>To do this, the first thing to do is create a folder to save the Svelte-related files. I’ll be creative and call this folder <code class="language-plaintext highlighter-rouge">Svelte</code>. From within it, I open a terminal and use the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm create vite@latest
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/install-svelte.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/install-svelte.jpg" alt="npm create vite@latest" class="lazy" />
</picture>
<p>I chose the project name as <code class="language-plaintext highlighter-rouge">counter</code>, the framework as <code class="language-plaintext highlighter-rouge">Svelte</code>, and the variant as <code class="language-plaintext highlighter-rouge">TypeScript</code>.</p>
<p>Still from the terminal, I use the commands:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>counter
npm <span class="nb">install
</span>npm run dev
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/svelte-run-dev.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/svelte-run-dev.jpg" alt="npm run dev" class="lazy" />
</picture>
<p>Using the link <code class="language-plaintext highlighter-rouge">http://localhost:5173</code>, I can see the HTML page generated by Svelte:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/vite-svelte.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/vite-svelte.jpg" alt="vite-svelte" class="lazy" />
</picture>
<h3 id="clean-up-svelte-code">Clean Up Svelte Code</h3>
<p>We can simplify the code to keep only the part that interests us, the <code class="language-plaintext highlighter-rouge">Counter</code> component. I modify the file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\App.svelte</code>:</p>
<pre><code class="language-svelte"><script lang="ts">
import Counter from "./lib/Counter.svelte";
</script>
<main>
<div class="card">
<Counter />
</div>
</main>
<style>
.card {
position: absolute;
top: 0;
left: 0;
padding: 2em;
}
</style>
</code></pre>
<p>I then add a style to <code class="language-plaintext highlighter-rouge">\svelte\counter\src\lib\Counter.svelte</code>:</p>
<pre><code class="language-svelte"><script lang="ts">
let count: number = 0;
const increment = () => {
count += 1;
};
</script>
<button on:click={increment}>
count is {count}
</button>
<style>
button:hover {
background-color: rgb(247, 218, 146);
color: rgb(30, 4, 4);
}
</style>
</code></pre>
<p>Finally, I modify the file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\main.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>
<p>This way, the component is inserted directly into the page. In my opinion, it’s not the best solution; I’ll explain a better method later.</p>
<p>After these changes, the Svelte preview shows this:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/svelte-clear.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/svelte-clear.jpg" alt="svelte-clear" class="lazy" />
</picture>
<h3 id="compile-svelte-code">Compile Svelte Code</h3>
<p>To use this component in Construct, I need to compile it and get the files to import into C3.</p>
<p>I use the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/npm-run-build.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/npm-run-build.jpg" alt="npm-run-build" class="lazy" />
</picture>
<p>This command creates two files: <code class="language-plaintext highlighter-rouge">\svelte\counter\dist\assets\index-XXXXX.css</code> and <code class="language-plaintext highlighter-rouge">\svelte\counter\dist\assets\index-XXXXX.js</code>. To use them with Construct, I need to copy them to the folders <code class="language-plaintext highlighter-rouge">\files\</code> and <code class="language-plaintext highlighter-rouge">\scripts\</code>. You can do this manually, but I recommend creating a script that handles moving the files to the correct location and renaming them more simply. I create the file <code class="language-plaintext highlighter-rouge">\svelte\counter\move-files.js</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">existsSync</span><span class="p">,</span> <span class="nx">readdirSync</span><span class="p">,</span> <span class="nx">copyFileSync</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fs</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">path</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">path</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">renameDist</span><span class="p">(</span><span class="nx">arg</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">match</span><span class="p">,</span> <span class="nx">replace</span><span class="p">,</span> <span class="nx">destination</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">arg</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Rename js and css in "</span><span class="p">${</span><span class="nx">dir</span><span class="p">}</span><span class="s2">"...`</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">existsSync</span><span class="p">(</span><span class="nx">dir</span><span class="p">))</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">files</span> <span class="o">=</span> <span class="nx">readdirSync</span><span class="p">(</span><span class="nx">dir</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">files</span><span class="p">);</span>
<span class="nx">files</span>
<span class="p">.</span><span class="nx">filter</span><span class="p">((</span><span class="nx">file</span><span class="p">)</span> <span class="o">=></span> <span class="nx">file</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">match</span><span class="p">))</span>
<span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">file</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">filePath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">dir</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">newFilePath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span>
<span class="nx">destination</span><span class="p">,</span>
<span class="nx">file</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">replace</span><span class="p">)</span>
<span class="p">);</span>
<span class="nx">copyFileSync</span><span class="p">(</span><span class="nx">filePath</span><span class="p">,</span> <span class="nx">newFilePath</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">dir</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">./dist/assets</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">renameDist</span><span class="p">({</span>
<span class="nx">dir</span><span class="p">,</span>
<span class="na">match</span><span class="p">:</span> <span class="nb">RegExp</span><span class="p">(</span><span class="sr">/</span><span class="se">\-(</span><span class="sr">.*</span><span class="se">?)\.</span><span class="sr">js/</span><span class="p">,</span> <span class="dl">"</span><span class="s2">gi</span><span class="dl">"</span><span class="p">),</span>
<span class="na">replace</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.js</span><span class="dl">"</span><span class="p">,</span>
<span class="na">destination</span><span class="p">:</span> <span class="dl">"</span><span class="s2">../../scripts/svelte</span><span class="dl">"</span><span class="p">,</span>
<span class="p">});</span>
<span class="nx">renameDist</span><span class="p">({</span>
<span class="nx">dir</span><span class="p">,</span>
<span class="na">match</span><span class="p">:</span> <span class="nb">RegExp</span><span class="p">(</span><span class="sr">/</span><span class="se">\-(</span><span class="sr">.*</span><span class="se">?)\.</span><span class="sr">css/</span><span class="p">,</span> <span class="dl">"</span><span class="s2">gi</span><span class="dl">"</span><span class="p">),</span>
<span class="na">replace</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.css</span><span class="dl">"</span><span class="p">,</span>
<span class="na">destination</span><span class="p">:</span> <span class="dl">"</span><span class="s2">../../files</span><span class="dl">"</span><span class="p">,</span>
<span class="p">});</span>
</code></pre></div></div>
<p>I modify the file <code class="language-plaintext highlighter-rouge">\svelte\counter\package.json</code>:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
</span><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vite build && npm run move-files"</span><span class="p">,</span><span class="w">
</span><span class="nl">"move-files"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node move-files.js"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>If the folders <code class="language-plaintext highlighter-rouge">\files</code> and <code class="language-plaintext highlighter-rouge">\scripts\svelte</code> don’t exist, create them. Run the command in the terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/npm-run-build-move.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/npm-run-build-move.jpg" alt="npm-run-build-move" class="lazy" />
</picture>
<h3 id="integrate-svelte-in-construct-3">Integrate Svelte in Construct 3</h3>
<p>I go back to the file <code class="language-plaintext highlighter-rouge">\scripts\importsForEvents.ts</code> and add:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//@ts-ignore</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">svelte</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./svelte/index.js</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div></div>
<p>Then I import the stylesheet:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+ System: On start of layout
-> Browser: Load stylesheet from "index.css"
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/load-stylesheet.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/load-stylesheet.jpg" alt="npm-run-build-move" class="lazy" />
</picture>
<p>I then show the project preview with Construct:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/preview-c3.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/preview-c3.jpg" alt="preview-c3" class="lazy" />
</picture>
<h3 id="insert-a-svelte-component-into-an-html-element">Insert a Svelte Component into an HTML Element</h3>
<p>So far, we’ve inserted a Svelte component into an HTML page using Construct. But it’s more useful to insert the component directly into the structure created by C3. To do this, create an HTML element in the project and assign it an ID (for example, <code class="language-plaintext highlighter-rouge">counter</code>).</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/html-element.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/html-element.jpg" alt="html-element" class="lazy" />
</picture>
<p>I then modify the file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\main.ts</code> to load the component directly into the Construct HTML element:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">counter</span><span class="dl">"</span><span class="p">),</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>
<p>But it’s better to tweak the code a bit more to allow Construct to dynamically load the component. To do this, I use <code class="language-plaintext highlighter-rouge">globalThis</code> to which I add a <code class="language-plaintext highlighter-rouge">Counter</code> property.</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kr">declare</span> <span class="nb">global</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">Counter</span><span class="p">:</span> <span class="nx">unknown</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span>
<span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">counter</span><span class="dl">"</span><span class="p">)</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span><span class="p">;</span>
</code></pre></div></div>
<p>From an Event Sheet, I use the JavaScript code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span><span class="p">();</span>
</code></pre></div></div>
<p>This way, I finally get the result:</p>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-04-using-typescript-and-svelte-in-construct/simple-click-button.gif" alt="Simple Click Button gif" /></p>
<!-- Posso in alternativa modificare l'interfaccia `Globals` in `\scripts\definitions\defs.ts`:
```ts
export interface Globals {
app: Function;
}
```
in modo da poter importare direttamente il modulo in `\scripts\globals.ts`
```ts
import type { Globals } from "./definitions/defs";
const Globals: Globals = {
//@ts-ignore
app: import("./svelte/index.js"),
};
export default Globals;
``` -->Samuelesamuele@stranianelli.comThe latest version of Construct 3 introduces an interesting feature: the ability to use TypeScript. Ashley wrote a comprehensive guide on the various steps to follow (you can find it here). Building upon this, I want to add some notes on how to integrate Svelte into a Construct project.Come Usare TypeScript e Svelte in Construct 32023-12-02T22:30:00+01:002023-12-02T22:30:00+01:00https://blog.stranianelli.com/using-typescript-and-svelte-in-construct-it<p>L’ultima versione di Construct 3 integra una novità interessante: la possibilità di usare TypeScript. Ashley ha scritto una buona guida sui vari passi da fare (la trovate <a href="https://www.construct.net/en/tutorials/using-typescript-construct-3003">qui</a>). Partendo da questa voglio aggiungere alcune note su come integrare Svelte all’interno di un progetto Construct.</p>
<p>Questi appunti sono divisi in due parti. Nella prima riassumo i passi principali per usare TypeScript all’interno di C3. È una versione sintetica della guida di Ashley. Nella seconda parte, invece, mi concentrerò su come usare Svelte, riproducendo l’esempio più semplice possibile:</p>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/simple-click-button.gif" alt="Simple Click Button gif" /></p>
<h2 id="typescript--construct">TypeScript & Construct</h2>
<h3 id="configurare-il-computer">Configurare il computer</h3>
<p>La prima cosa da fare è accertarsi di aver installato <a href="https://nodejs.org/">Node.js</a> sul proprio computer. In secondo luogo, se non lo abbiamo già fatto, dobbiamo installare TypeScript da terminale usando il comando <code class="language-plaintext highlighter-rouge">npm install -g typescript</code>. Possiamo controllare la versione installata usando il comando <code class="language-plaintext highlighter-rouge">tsc --version</code>.</p>
<p>Ashley riporta anche questo potenziale errore</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/error.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/error.jpg" alt="error" class="lazy" />
</picture>
<h3 id="creare-il-progetto">Creare il progetto</h3>
<p>Dopo aver impostato il proprio computer possiamo creare un progetto in Construct. Salviamo il progetto “As Folder” usando il comando <code class="language-plaintext highlighter-rouge">Menu ► Project ► Save as ► Save as project folder...</code></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/save-as-project-folder.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/save-as-project-folder.jpg" alt="Menu ► Project ► Save as ► Save as project folder..." class="lazy" />
</picture>
<p>Il passo successivo è scegliere la cartella <code class="language-plaintext highlighter-rouge">Scripts</code>: usando il tasto destro del mouse clicchiamo su <code class="language-plaintext highlighter-rouge">TypeScript ► Set up TypeScript</code></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/set-up-typescript.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/set-up-typescript.jpg" alt="TypeScript ► Set up TypeScript" class="lazy" />
</picture>
<p>Poiché lavoreremo sui file nel pc ma testeremo le modifiche tramite Construct è una buona idea abilitare l’opzione “<em>Auto reload all on preview</em>”</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/auto-reload-all-on-preview.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/auto-reload-all-on-preview.jpg" alt="Auto reload all on preview" class="lazy" />
</picture>
<p>Adesso possiamo aprire il progetto con il nostro editor di testo preferito. Nel mio caso utilizzo Visual Studio Code.</p>
<p>In VS Code uso la combinazione di tasti <code class="language-plaintext highlighter-rouge">Ctrl + Shift + B</code> per selezionare <code class="language-plaintext highlighter-rouge">tsc: watch</code> e abilitare la compilazione automatica dei file <code class="language-plaintext highlighter-rouge">.ts</code> in <code class="language-plaintext highlighter-rouge">.js</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/ts-watch.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/ts-watch.jpg" alt="tsc: watch" class="lazy" />
</picture>
<h3 id="utilities">Utilities</h3>
<p>C3 imposta il progetto con tutti i file fondamentali ma possiamo aggiungere alcuni file per semplificare il nostro futuro workflow.</p>
<p>Creo il file <code class="language-plaintext highlighter-rouge">scripts/definitions/customGlobal.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="p">{};</span>
<span class="kr">declare</span> <span class="nb">global</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">g_runtime</span><span class="p">:</span> <span class="nx">IRuntime</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/custom-global.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/custom-global.jpg" alt="scripts/definitions/customGlobal.ts" class="lazy" />
</picture>
<p>In questo modo posso personalizzare <code class="language-plaintext highlighter-rouge">globalThis</code>.</p>
<p>Aggiungo poi il file <code class="language-plaintext highlighter-rouge">scripts/definitions/defs.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kr">interface</span> <span class="nx">Globals</span> <span class="p">{}</span>
</code></pre></div></div>
<p>Questa interfaccia sarà utile per aggiungere variabili globali all’applicazione. Per usarla, creo il file <code class="language-plaintext highlighter-rouge">scripts/globals.ts</code></p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="kd">type</span> <span class="p">{</span> <span class="nx">Globals</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./definitions/defs</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Globals</span><span class="p">:</span> <span class="nx">Globals</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">Globals</span><span class="p">;</span>
</code></pre></div></div>
<p>Adesso è il momento di sistemare i file generati da Construct. Apro <code class="language-plaintext highlighter-rouge">scripts/main.ts</code>, elimino tutto il contenuto e al suo posto scrivo:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">runOnStartup</span><span class="p">(</span><span class="k">async</span> <span class="p">(</span><span class="nx">runtime</span><span class="p">:</span> <span class="nx">IRuntime</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">globalThis</span><span class="p">.</span><span class="nx">g_runtime</span> <span class="o">=</span> <span class="nx">runtime</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Questo codice mi permette di richiamare le runtime direttamente da C3.</p>
<p>Infine modifico il file <code class="language-plaintext highlighter-rouge">importsForEvents.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">Globals</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./globals.js</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div></div>
<p>Questo file mi permette di far comunicare gli Event Sheets di Construct direttamente con il codice generato a partire da TypeScript.</p>
<h2 id="svelte--construct">Svelte & Construct</h2>
<h3 id="impostare-svelte">Impostare Svelte</h3>
<p>Bene, fin qui la parte legata a configurare C3 e TypeScript. Ma adesso è il momento di aggiungere <a href="https://svelte.dev/">Svelte</a>.</p>
<p>Ricordo lo scopo di questo tutorial: creare un pulsante che conta i click. Ovvero replicare l’esempio base.</p>
<p>Per farlo la prima cosa da fare è creare una cartella in cui salvare i file legati a Svelte. Con molta fantasia chiamerò questa cartella <code class="language-plaintext highlighter-rouge">Svelte</code>. Dal suo interno apro un terminale e uso il comando</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm create vite@latest
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/install-svelte.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/install-svelte.jpg" alt="npm create vite@latest" class="lazy" />
</picture>
<p>Ho scelto come nome del progetto <code class="language-plaintext highlighter-rouge">counter</code>, come framework <code class="language-plaintext highlighter-rouge">Svelte</code>, come variante <code class="language-plaintext highlighter-rouge">TypeScript</code>.</p>
<p>Sempre da terminale uso i comandi:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>counter
npm <span class="nb">install
</span>npm run dev
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/svelte-run-dev.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/svelte-run-dev.jpg" alt="npm run dev" class="lazy" />
</picture>
<p>Usando il link <code class="language-plaintext highlighter-rouge">http://localhost:5173</code> posso vedere la pagina html generata da Svelte</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/vite-svelte.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/vite-svelte.jpg" alt="vite-svelte" class="lazy" />
</picture>
<h3 id="pulire-il-codice-di-svelte">Pulire il codice di Svelte</h3>
<p>Possiamo semplificare il codice per tenere solamente la parte che ci interessa, ovvero il componente <code class="language-plaintext highlighter-rouge">Counter</code>. Modifico il file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\App.svelte</code>:</p>
<pre><code class="language-svelte"><script lang="ts">
import Counter from "./lib/Counter.svelte";
</script>
<main>
<div class="card">
<Counter />
</div>
</main>
<style>
.card {
position: absolute;
top: 0;
left: 0;
padding: 2em;
}
</style>
</code></pre>
<p>Aggiungo poi uno stile a <code class="language-plaintext highlighter-rouge">\svelte\counter\src\lib\Counter.svelte</code>:</p>
<pre><code class="language-svelte"><script lang="ts">
let count: number = 0;
const increment = () => {
count += 1;
};
</script>
<button on:click={increment}>
count is {count}
</button>
<style>
button:hover {
background-color: rgb(247, 218, 146);
color: rgb(30, 4, 4);
}
</style>
</code></pre>
<p>Infine modifico il file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\main.ts</code>:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>
<p>In questo modo il componente viene inserito direttamente nella pagina. Secondo me non è la soluzione migliore, più avanti spiegherò un metodo migliore.</p>
<p>Dopo queste modifiche l’anteprima di Svelte mostra questo:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/svelte-clear.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/svelte-clear.jpg" alt="svelte-clear" class="lazy" />
</picture>
<h3 id="compilare-il-codice-di-svelte">Compilare il codice di Svelte</h3>
<p>Per usare questo componente in Construct devo prima compilarlo e ottenere i file da importare in C3.</p>
<p>Uso il comando</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/npm-run-build.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/npm-run-build.jpg" alt="npm-run-build" class="lazy" />
</picture>
<p>Questo comando crea due file: <code class="language-plaintext highlighter-rouge">\svelte\counter\dist\assets\index-XXXXX.css</code> e <code class="language-plaintext highlighter-rouge">\svelte\counter\dist\assets\index-XXXXX.js</code>. Per poterli usare con construct devo copiarli nelle cartelle <code class="language-plaintext highlighter-rouge">\files\</code> e <code class="language-plaintext highlighter-rouge">\scripts\</code>. Possiamo farlo a mano.</p>
<p>Ma consiglio di creare uno script che si occupi di spostare i file nella posizione corretta e di rinominarli in maniera più semplice. Creo il file <code class="language-plaintext highlighter-rouge">\svelte\counter\move-files.js</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">existsSync</span><span class="p">,</span> <span class="nx">readdirSync</span><span class="p">,</span> <span class="nx">copyFileSync</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">fs</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">path</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">path</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">renameDist</span><span class="p">(</span><span class="nx">arg</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">match</span><span class="p">,</span> <span class="nx">replace</span><span class="p">,</span> <span class="nx">destination</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">arg</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Rename js and css in "</span><span class="p">${</span><span class="nx">dir</span><span class="p">}</span><span class="s2">"...`</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">existsSync</span><span class="p">(</span><span class="nx">dir</span><span class="p">))</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">files</span> <span class="o">=</span> <span class="nx">readdirSync</span><span class="p">(</span><span class="nx">dir</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">files</span><span class="p">);</span>
<span class="nx">files</span>
<span class="p">.</span><span class="nx">filter</span><span class="p">((</span><span class="nx">file</span><span class="p">)</span> <span class="o">=></span> <span class="nx">file</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">match</span><span class="p">))</span>
<span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">file</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">filePath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">dir</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">newFilePath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span>
<span class="nx">destination</span><span class="p">,</span>
<span class="nx">file</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">replace</span><span class="p">)</span>
<span class="p">);</span>
<span class="nx">copyFileSync</span><span class="p">(</span><span class="nx">filePath</span><span class="p">,</span> <span class="nx">newFilePath</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">dir</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">./dist/assets</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">renameDist</span><span class="p">({</span>
<span class="nx">dir</span><span class="p">,</span>
<span class="na">match</span><span class="p">:</span> <span class="nb">RegExp</span><span class="p">(</span><span class="sr">/</span><span class="se">\-(</span><span class="sr">.*</span><span class="se">?)\.</span><span class="sr">js/</span><span class="p">,</span> <span class="dl">"</span><span class="s2">gi</span><span class="dl">"</span><span class="p">),</span>
<span class="na">replace</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.js</span><span class="dl">"</span><span class="p">,</span>
<span class="na">destination</span><span class="p">:</span> <span class="dl">"</span><span class="s2">../../scripts/svelte</span><span class="dl">"</span><span class="p">,</span>
<span class="p">});</span>
<span class="nx">renameDist</span><span class="p">({</span>
<span class="nx">dir</span><span class="p">,</span>
<span class="na">match</span><span class="p">:</span> <span class="nb">RegExp</span><span class="p">(</span><span class="sr">/</span><span class="se">\-(</span><span class="sr">.*</span><span class="se">?)\.</span><span class="sr">css/</span><span class="p">,</span> <span class="dl">"</span><span class="s2">gi</span><span class="dl">"</span><span class="p">),</span>
<span class="na">replace</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.css</span><span class="dl">"</span><span class="p">,</span>
<span class="na">destination</span><span class="p">:</span> <span class="dl">"</span><span class="s2">../../files</span><span class="dl">"</span><span class="p">,</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Modifico il file <code class="language-plaintext highlighter-rouge">\svelte\counter\package.json</code>:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
</span><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vite build && npm run move-files"</span><span class="p">,</span><span class="w">
</span><span class="nl">"move-files"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node move-files.js"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Se non esistono, creo le cartelle <code class="language-plaintext highlighter-rouge">\files</code> e <code class="language-plaintext highlighter-rouge">\scripts\svelte</code>. Eseguo da terminale il comando</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run build
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/npm-run-build-move.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/npm-run-build-move.jpg" alt="npm-run-build-move" class="lazy" />
</picture>
<h3 id="integrare-svelte-in-construct-3">Integrare Svelte in Construct 3</h3>
<p>Torno al file <code class="language-plaintext highlighter-rouge">\scripts\importsForEvents.ts</code> e aggiungo</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//@ts-ignore</span>
<span class="k">import</span> <span class="o">*</span> <span class="k">as</span> <span class="nx">svelte</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./svelte/index.js</span><span class="dl">"</span><span class="p">;</span>
</code></pre></div></div>
<p>Poi importo il foglio di stile</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+ System: On start of layout
-> Browser: Load stylesheet from "index.css"
</code></pre></div></div>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/load-stylesheet.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/load-stylesheet.jpg" alt="npm-run-build-move" class="lazy" />
</picture>
<p>Mostro quindi l’anteprima del progetto con Construct:</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/preview-c3.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/preview-c3.jpg" alt="preview-c3" class="lazy" />
</picture>
<h3 id="inserire-un-componente-svelte-in-un-elemento-html">Inserire un componente Svelte in un Elemento HTML</h3>
<p>Fin qui abbiamo inserito un componente Svelte in una pagina HTML usando Construct. Ma è più utile inserire il componente direttamente nella struttura creata da C3. Per farlo creiamo un elemento HTML nel progetto e gli assegniamo un ID (per esempio <code class="language-plaintext highlighter-rouge">counter</code>).</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/html-element.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/html-element.jpg" alt="html-element" class="lazy" />
</picture>
<p>Modifico quindi il file <code class="language-plaintext highlighter-rouge">\svelte\counter\src\main.ts</code> in modo da poter caricare direttamente il componente nell’elemento HTML di Construct:</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">counter</span><span class="dl">"</span><span class="p">),</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>
<p>Ma conviene modificare ancora un po’ il codice per permettere a Construct di caricare in maniera dinamica il componente. Per farlo uso <code class="language-plaintext highlighter-rouge">globalThis</code> a cui aggiungo una proprietà <code class="language-plaintext highlighter-rouge">Counter</code>.</p>
<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">./app.css</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./App.svelte</span><span class="dl">"</span><span class="p">;</span>
<span class="kr">declare</span> <span class="nb">global</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">Counter</span><span class="p">:</span> <span class="nx">unknown</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span>
<span class="k">new</span> <span class="nx">App</span><span class="p">({</span>
<span class="na">target</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">counter</span><span class="dl">"</span><span class="p">)</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span>
<span class="p">});</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span><span class="p">;</span>
</code></pre></div></div>
<p>Da un Event Sheet uso il codice JavaScript</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">globalThis</span><span class="p">.</span><span class="nx">Counter</span><span class="p">();</span>
</code></pre></div></div>
<p>In questo modo ottengo finalmente il risultato:</p>
<p><img src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-12-02-using-typescript-and-svelte-in-construct-it/simple-click-button.gif" alt="Simple Click Button gif" /></p>
<!-- Posso in alternativa modificare l'interfaccia `Globals` in `\scripts\definitions\defs.ts`:
```ts
export interface Globals {
app: Function;
}
```
in modo da poter importare direttamente il modulo in `\scripts\globals.ts`
```ts
import type { Globals } from "./definitions/defs";
const Globals: Globals = {
//@ts-ignore
app: import("./svelte/index.js"),
};
export default Globals;
``` -->Samuelesamuele@stranianelli.comL’ultima versione di Construct 3 integra una novità interessante: la possibilità di usare TypeScript. Ashley ha scritto una buona guida sui vari passi da fare (la trovate qui). Partendo da questa voglio aggiungere alcune note su come integrare Svelte all’interno di un progetto Construct.Viewing ArcGIS Pro Coordinates in Google Maps2023-07-23T17:30:00+02:002023-07-23T17:30:00+02:00https://blog.stranianelli.com/how-to-view-arcgis-pro-coordinates-in-google-maps<p>Continuing the series of the articles on ArcGIS Pro, today we will see how to view the coordinates of a point in Google Maps. This is a very useful operation when you have to locate a point on a map and you have the coordinates in a different format than the one used by Google Maps. In this case, we will see how to convert the coordinates of a point from the format used by ArcGIS Pro to the format used by Google Maps.</p>
<p>First, we need the ArcGIS Pro coordinates of the point we want to locate on Google Maps. To do this, we open the map in ArcGIS Pro and right-click on the point we want to locate. Then we select <code class="language-plaintext highlighter-rouge">Copy Coordinates</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 01.jpg" alt="" class="lazy" />
</picture>
<p>We obtain the coordinates of the point in the format used by ArcGIS Pro:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>761.114,86E 5.036.590,18N m
</code></pre></div></div>
<p>Now we need to convert the coordinates to the format used by Google Maps. To do this, we can simply usa another command in ArcGIS Pro. Right-click again on the point we want to locate and select <code class="language-plaintext highlighter-rouge">Convert Coordinates</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 02.jpg" alt="" class="lazy" />
</picture>
<p>We can choose between different formats:</p>
<ul>
<li><strong>DD</strong>: Convert to Decimal Degrees - <code class="language-plaintext highlighter-rouge">12,3385427°E 45,4340893°N</code></li>
<li><strong>DDM</strong>: Convert to Decimal Degrees Minutes - <code class="language-plaintext highlighter-rouge">12°20,3059545'E 45°26,0473060'N </code></li>
<li><strong>DMS</strong>: Convert to Degrees Minutes Seconds - <code class="language-plaintext highlighter-rouge">12°20'17"E 45°26'2"N</code></li>
<li><strong>MGRS</strong>: Convert to Military Grid Reference System - <code class="language-plaintext highlighter-rouge">33TTL 91795 34615</code></li>
<li><strong>USNG</strong>: Convert to United States National Grid - <code class="language-plaintext highlighter-rouge">33T TL 91797 34628</code></li>
<li><strong>UTM</strong>: Convert to Universal Transverse Mercator - <code class="language-plaintext highlighter-rouge">33T 291801 5034620</code></li>
</ul>
<p>For ours purposes, we can choose <code class="language-plaintext highlighter-rouge">DDM - Decimal Degrees Minutes</code> or <code class="language-plaintext highlighter-rouge">MGRS - Military Grid Reference System</code>. In this case, we choose <code class="language-plaintext highlighter-rouge">DDM</code>.</p>
<p>ArcGIS Pro will copy the coordinates to the clipboard in the format we have chosen. We can use the coordinates in the format we have chosen to locate the point on Google Maps via a simple search.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 03.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 03.jpg" alt="" class="lazy" />
</picture>
<p>From this, we can see the Stree View of the point we have located.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 04.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 04.jpg" alt="" class="lazy" />
</picture>
<p>We can also use the converted coordinates to locate the point on Google Earth.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 05.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-23-how-to-view-arcgis-pro-coordinates-in-google-maps/Come vedere un punto su Google Maps - 05.jpg" alt="" class="lazy" />
</picture>Samuelesamuele@stranianelli.comContinuing the series of the articles on ArcGIS Pro, today we will see how to view the coordinates of a point in Google Maps. This is a very useful operation when you have to locate a point on a map and you have the coordinates in a different format than the one used by Google Maps. In this case, we will see how to convert the coordinates of a point from the format used by ArcGIS Pro to the format used by Google Maps.How To Add Google Maps To ArcGIS Pro2023-07-16T19:00:00+02:002023-07-16T19:00:00+02:00https://blog.stranianelli.com/how-to-add-google-maps-to-arcgis-pro<p>During the past few weeks, I started using ArcGIS Pro, perhaps the most powerful GIS software available on the market. ArcGIS Pro is a newer and advanced version of the software ArcMap, developed by Esri. ArcGIS Pro offers a wide range of tools and functionalities for analyzing and visualizing geographic data. You can create customized maps, analyze data, perform spatial analysis, create geoprocessing models, and much more. The problem is that there are no affordable courses available to learn how to use it. So, I’m facing a series of issues, often trivial ones, but they are slowing me down.</p>
<p>One of these issues is how to add Google Maps data layers to the maps. In other software (e.g., QGIS), you can use the <code class="language-plaintext highlighter-rouge">Add XYZ Tiles Layer (TMS)</code> function to directly connect to Google services. ArcGIS, on the other hand, uses a different command: <code class="language-plaintext highlighter-rouge">Add data from Path</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Add Data From Path - 01.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Add Data From Path - 01.jpg" alt="" class="lazy" />
</picture>
<p>To use this function, we need to select the <code class="language-plaintext highlighter-rouge">Map Menu</code>, then go to <code class="language-plaintext highlighter-rouge">Layer</code> and click on <code class="language-plaintext highlighter-rouge">Add Data</code>. Among the various available options, we choose <code class="language-plaintext highlighter-rouge">Data From Path</code>.</p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Add Data From Path - 02.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Add Data From Path - 02.jpg" alt="" class="lazy" />
</picture>
<p>Here, we can enter the URL for the maps and the <code class="language-plaintext highlighter-rouge">Service Type</code> to use. We can leave the type set to <em>Automatic</em>. But when it comes to the URL, there is some research to be done. First, we need to find the URL of the Google Maps service. Fortunately, someone has dedicated some time to this issue. The “Southern California Government GIS User Group” published <a href="https://socalgis.org/2014/02/05/my-adventure-with-google-maps-in-arcmap/">a post in 2014</a> (updated in <a href="https://socalgis.org/2020/12/02/add-google-maps-to-arcmap-and-pro/">2020</a>) on this topic a few years ago: it’s a good starting point. In this post, they explain how to find the URL of the Google Maps service. And indeed, starting from there, I found a series of URLs that work with ArcGIS Pro. These are the links I found: [list of URLs].</p>
<p><strong>Google Map</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Map.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Map.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt1.google.com/vt/lyrs=r&x={col}&y={row}&z={level}</code></p>
<p><strong>Google Satellite Hybrid</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Satellite Hybrid.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Satellite Hybrid.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt1.google.com/vt/lyrs=y&x={col}&y={row}&z={level}</code></p>
<p><strong>Google Earth Basemap</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Earth Basemap.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Earth Basemap.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt1.google.com/vt/lyrs=s&x={col}&y={row}&z={level}</code></p>
<p><strong>Google Labels</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Labels.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Labels.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt.google.com/vt/lyrs=h&hl=en&z={level}&x={col}&y={row}</code> (Note: instead of <code class="language-plaintext highlighter-rouge">hl=en</code>, you can insert a different language, e.g.,<code class="language-plaintext highlighter-rouge"> hl=it</code>)</p>
<p><strong>Google Aerial</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Aerial.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Aerial.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt.google.com/vt/lyrs=s&hl=en&z={level}&x={col}&y={row}</code></p>
<p><strong>Google Terrain</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Terrain.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Terrain.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt1.google.com/vt/lyrs=p&x={col}&y={row}&z={level}</code></p>
<p><strong>Google Roads</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Roads.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Google Roads.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://mt1.google.com/vt/lyrs=h&x={col}&y={row}&z={level}</code></p>
<p><strong>OpenStreetMap</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://a.tile.openstreetmap.org/{level}/{col}/{row}.png</code></p>
<p><strong>OpenStreetMap Blueprint</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Blueprint.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Blueprint.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/80be160f0ca1413d898ad4e90d197278/resources/styles/root.json</code></p>
<p><strong>OpenStreetMap Light Gray Canvas</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Light Gray Canvas.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Light Gray Canvas.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/29a71939af7a498584f44c4feca7249b/resources/styles/root.json</code></p>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/1932e7d4432d45dabc0d4d13109c1f09/resources/styles/root.json</code></p>
<p><strong>OpenStreetMap Dark Gray Canvas</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Dark Gray Canvas.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Dark Gray Canvas.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/b49a8db3fe6e4f9f99cb713aee150e8d/resources/styles/root.json</code></p>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/cb38f2afc497482a85579dce4c3ff4ed/resources/styles/root.json</code></p>
<p><strong>OpenStreetMap Navigation</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Navigation.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Navigation.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/f886634ab3f349f18199bf554bf75ee3/resources/styles/root.json</code></p>
<p><strong>OpenStreetMap Navigation Dark</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Navigation Dark.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/OpenStreetMap Navigation Dark.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://www.arcgis.com/sharing/rest/content/items/92966c7ebc3d4ddaac34050560568bad/resources/styles/root.json</code></p>
<p><strong>Stamen Toner</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Toner.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Toner.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png</code></p>
<p><strong>Stamen Terrain</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Terrain.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Terrain.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg</code></p>
<p><strong>Stamen Watercolor</strong></p>
<picture>
<source type="image/webp" data-srcset="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Watercolor.webp" />
<img data-src="https://raw.githubusercontent.com/el3um4s/strani-anelli-blog/master/_posts/2023/2023-07-16-how-to-add-google-maps-to-arcgis-pro/Stamen Watercolor.jpg" alt="" class="lazy" />
</picture>
<p><code class="language-plaintext highlighter-rouge">https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg</code></p>Samuelesamuele@stranianelli.comDuring the past few weeks, I started using ArcGIS Pro, perhaps the most powerful GIS software available on the market. ArcGIS Pro is a newer and advanced version of the software ArcMap, developed by Esri. ArcGIS Pro offers a wide range of tools and functionalities for analyzing and visualizing geographic data. You can create customized maps, analyze data, perform spatial analysis, create geoprocessing models, and much more. The problem is that there are no affordable courses available to learn how to use it. So, I’m facing a series of issues, often trivial ones, but they are slowing me down.