o3-mini-high - prototyp MS Paint gotowy w 19s

o3-mini-high - prototyp MS Paint gotowy w 19s
pradoslaw
Administrator
  • Rejestracja:około 8 lat
  • Ostatnio:minuta
  • Lokalizacja:Wrocław
  • Postów:92
4

To są zaledwie 3 prompty:

  1. Zbuduj MS Paint z zaawansowanymi ustawieniami. Użyj CSS, JS i HTML w jednym pliku HTML - 19s
  2. Dodaj funkcje "cofnij" "wróć" zmianę - 32s
  3. Niech UI programu korzysta z kolorystyki serwisu 4programmers.net 32s

Wszystko zadziałało przy pierwszej próbie odpalenia. Zero bugów. Czy to nie jest gigantyczny postęp?

Markup 2025-02-13 at 13.30.37.png

Kopiuj
<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8" />
  <title>Advanced MS Paint z Cofnij/Wróć</title>
  <style>
    /* Ogólna kolorystyka inspirowana 4programmers.net */
    body {
      margin: 0;
      font-family: Arial, sans-serif;
      background-color: #ecf0f1; /* jasny szary */
    }
    /* Pasek narzędzi – ciemne tło z jasnym tekstem */
    #toolbar {
      background-color: #2c3e50; /* ciemny niebiesko-szary */
      color: #ecf0f1; /* jasny tekst */
      padding: 10px;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
    }
    #toolbar > * {
      margin: 5px;
    }
    #toolbar label {
      margin-right: 5px;
    }
    /* Stylizacja pól wyboru, inputów i select */
    #toolbar input[type="color"],
    #toolbar input[type="range"],
    #toolbar select {
      padding: 5px;
      border-radius: 3px;
      border: none;
    }
    /* Przyciski – pomarańczowe akcenty */
    #toolbar button {
      background-color: #d35400; /* intensywny pomarańczowy */
      color: #ecf0f1;
      border: none;
      padding: 8px 12px;
      cursor: pointer;
      border-radius: 3px;
      transition: background-color 0.3s;
    }
    #toolbar button:hover {
      background-color: #e67e22;
    }
    /* Kontener płótna */
    #canvasContainer {
      position: relative;
      border: 1px solid #bdc3c7;
      margin: 10px auto;
      background-color: #fff;
      width: 800px;
      height: 600px;
    }
    canvas {
      position: absolute;
      left: 0;
      top: 0;
    }
    /* Główny canvas (na spodzie) */
    #canvas {
      z-index: 1;
    }
    /* Tymczasowy canvas do podglądu kształtów */
    #tempCanvas {
      z-index: 2;
    }
  </style>
</head>
<body>
  <div id="toolbar">
    <label for="tool">Narzędzie:</label>
    <select id="tool">
      <option value="pencil">Ołówek</option>
      <option value="line">Linia</option>
      <option value="rectangle">Prostokąt</option>
      <option value="circle">Koło</option>
      <option value="eraser">Gumka</option>
    </select>

    <label for="brushSize">Grubość pędzla:</label>
    <input type="range" id="brushSize" min="1" max="50" value="5" />

    <label for="strokeColor">Kolor obrysu:</label>
    <input type="color" id="strokeColor" value="#000000" />

    <label for="fillColor">Kolor wypełnienia:</label>
    <input type="color" id="fillColor" value="#000000" />

    <label for="fillShape">Wypełnienie:</label>
    <input type="checkbox" id="fillShape" />

    <button id="clearCanvas">Wyczyść</button>
    <button id="saveCanvas">Zapisz</button>
    <button id="undo">Cofnij</button>
    <button id="redo">Wróć</button>
  </div>

  <div id="canvasContainer">
    <canvas id="canvas" width="800" height="600"></canvas>
    <canvas id="tempCanvas" width="800" height="600"></canvas>
  </div>

  <script>
    // Pobierz elementy i konteksty
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    const tempCanvas = document.getElementById('tempCanvas');
    const tempCtx = tempCanvas.getContext('2d');

    const toolSelect = document.getElementById('tool');
    const brushSize = document.getElementById('brushSize');
    const strokeColor = document.getElementById('strokeColor');
    const fillColor = document.getElementById('fillColor');
    const fillShape = document.getElementById('fillShape');
    const clearCanvasBtn = document.getElementById('clearCanvas');
    const saveCanvasBtn = document.getElementById('saveCanvas');
    const undoBtn = document.getElementById('undo');
    const redoBtn = document.getElementById('redo');

    let drawing = false;
    let currentTool = toolSelect.value;
    let startX = 0, startY = 0;

    // Stosy do cofania i ponawiania zmian
    let undoStack = [];
    let redoStack = [];

    // Zapisz aktualny stan płótna
    function pushState() {
      // Nowe działanie – czyścimy stos do ponawiania
      redoStack = [];
      // Zapisujemy aktualny stan (ImageData)
      undoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
    }

    function undo() {
      if (undoStack.length > 0) {
        // Zapisz bieżący stan do stosu "redo"
        redoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
        // Przywróć ostatni stan
        const state = undoStack.pop();
        ctx.putImageData(state, 0, 0);
      }
    }

    function redo() {
      if (redoStack.length > 0) {
        // Zapisz bieżący stan do stosu "undo"
        undoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
        // Przywróć ostatni stan ze stosu "redo"
        const state = redoStack.pop();
        ctx.putImageData(state, 0, 0);
      }
    }

    // Inicjalizacja – zapis pustego płótna
    pushState();

    // Aktualizacja narzędzia przy zmianie wyboru
    toolSelect.addEventListener('change', function () {
      currentTool = this.value;
    });

    // Obsługa zdarzeń myszy na tymczasowym canvasie
    tempCanvas.addEventListener('mousedown', startDrawing);
    tempCanvas.addEventListener('mousemove', draw);
    tempCanvas.addEventListener('mouseup', finishDrawing);
    tempCanvas.addEventListener('mouseout', finishDrawing);

    function getMousePos(e) {
      const rect = tempCanvas.getBoundingClientRect();
      return {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top,
      };
    }

    function startDrawing(e) {
      drawing = true;
      const pos = getMousePos(e);
      startX = pos.x;
      startY = pos.y;

      // Dla narzędzi typu "pencil" i "eraser" zaczynamy natychmiast ścieżkę
      if (currentTool === 'pencil' || currentTool === 'eraser') {
        ctx.beginPath();
        ctx.moveTo(startX, startY);
      }
    }

    function draw(e) {
      if (!drawing) return;
      const pos = getMousePos(e);
      const mouseX = pos.x;
      const mouseY = pos.y;

      if (currentTool === 'pencil') {
        ctx.lineTo(mouseX, mouseY);
        ctx.strokeStyle = strokeColor.value;
        ctx.lineWidth = brushSize.value;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        ctx.stroke();
      } else if (currentTool === 'eraser') {
        ctx.globalCompositeOperation = 'destination-out';
        ctx.lineTo(mouseX, mouseY);
        ctx.strokeStyle = 'rgba(0,0,0,1)';
        ctx.lineWidth = brushSize.value;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        ctx.stroke();
        ctx.globalCompositeOperation = 'source-over';
      } else {
        // Dla narzędzi kształtów – czyścimy podgląd i rysujemy tymczasowy kształt
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        tempCtx.lineWidth = brushSize.value;
        tempCtx.strokeStyle = strokeColor.value;
        tempCtx.fillStyle = fillColor.value;
        tempCtx.lineCap = 'round';
        tempCtx.lineJoin = 'round';

        if (currentTool === 'line') {
          tempCtx.beginPath();
          tempCtx.moveTo(startX, startY);
          tempCtx.lineTo(mouseX, mouseY);
          tempCtx.stroke();
        } else if (currentTool === 'rectangle') {
          const width = mouseX - startX;
          const height = mouseY - startY;
          if (fillShape.checked) {
            tempCtx.fillRect(startX, startY, width, height);
          }
          tempCtx.strokeRect(startX, startY, width, height);
        } else if (currentTool === 'circle') {
          const radius = Math.sqrt(Math.pow(mouseX - startX, 2) + Math.pow(mouseY - startY, 2));
          tempCtx.beginPath();
          tempCtx.arc(startX, startY, radius, 0, Math.PI * 2);
          if (fillShape.checked) {
            tempCtx.fill();
          }
          tempCtx.stroke();
        }
      }
    }

    function finishDrawing(e) {
      if (!drawing) return;
      drawing = false;
      const pos = getMousePos(e);
      const mouseX = pos.x;
      const mouseY = pos.y;

      // Dla narzędzi kształtów – przenosimy tymczasowy kształt na główny canvas
      if (currentTool === 'line' || currentTool === 'rectangle' || currentTool === 'circle') {
        ctx.lineWidth = brushSize.value;
        ctx.strokeStyle = strokeColor.value;
        ctx.fillStyle = fillColor.value;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';

        if (currentTool === 'line') {
          ctx.beginPath();
          ctx.moveTo(startX, startY);
          ctx.lineTo(mouseX, mouseY);
          ctx.stroke();
        } else if (currentTool === 'rectangle') {
          const width = mouseX - startX;
          const height = mouseY - startY;
          if (fillShape.checked) {
            ctx.fillRect(startX, startY, width, height);
          }
          ctx.strokeRect(startX, startY, width, height);
        } else if (currentTool === 'circle') {
          const radius = Math.sqrt(Math.pow(mouseX - startX, 2) + Math.pow(mouseY - startY, 2));
          ctx.beginPath();
          ctx.arc(startX, startY, radius, 0, Math.PI * 2);
          if (fillShape.checked) {
            ctx.fill();
          }
          ctx.stroke();
        }
        // Czyścimy warstwę podglądu
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
      }
      
      // Po zakończeniu rysowania zapisujemy aktualny stan dla cofania
      pushState();
    }

    // Czyścimy canvas po kliknięciu przycisku "Wyczyść"
    clearCanvasBtn.addEventListener('click', function () {
      pushState(); // Zapisz stan przed czyszczeniem
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      pushState(); // Zapisz stan pustego płótna
    });

    // Zapisujemy rysunek jako obrazek
    saveCanvasBtn.addEventListener('click', function () {
      // Łączymy główny canvas z ewentualnym podglądem
      const mergedCanvas = document.createElement('canvas');
      mergedCanvas.width = canvas.width;
      mergedCanvas.height = canvas.height;
      const mergedCtx = mergedCanvas.getContext('2d');
      mergedCtx.drawImage(canvas, 0, 0);
      mergedCtx.drawImage(tempCanvas, 0, 0);
      const link = document.createElement('a');
      link.download = 'my_painting.png';
      link.href = mergedCanvas.toDataURL();
      link.click();
    });

    // Przypisujemy funkcje cofania i ponawiania do przycisków
    undoBtn.addEventListener('click', undo);
    redoBtn.addEventListener('click', redo);
  </script>
</body>
</html>
loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:około 7 godzin
  • Postów:1583
0
pradoslaw napisał(a):

Wszystko zadziałało przy pierwszej próbie odpalenia. Zero bugów. Czy to nie jest gigantyczny postęp?

Jeśli w Javascripcie i HTMLu to aktualnie regres bo tego uczą na bootcampach.


Przetrzyma wszystko
AN
  • Rejestracja:prawie 11 lat
  • Ostatnio:41 minut
  • Postów:973
0

No ogólnie spoko tylko to jest bardzo odtwórcze i nieskomplikowane.

Co nie zmienia faktu, że jakby ktoś pokazał Ci takie "AI" 7 lat temu to każdemu oczy by wyskoczyły :D Ale teraz już to nie robi takiego wrażenia bo się człowiek przyzwyczaił


Zdalna praca dla Senior Python Developerów --> PW
pradoslaw
Faktycznie to jest odtwórcze, ale nie oszukujmy się ponad 90% rzeczy, które budujemy jest odtwórcze. :) Czy tak nie jest?
AN
Jest ale nie aż w takim stopniu. Weź np. zadanie typu napisz snake (bardzo podobne) - AI ma 10000 projektów na githubie z których tego się nauczy. Ale nie ma dostępu do 10000 projektów skali np. 4programmers czy facebooka. No i też skala, to jest zamknięte w jednym pliku, a jak projekt ma 1000 plików to już może być problemem
pradoslaw
Pełna zgoda :)
loza_prowizoryczna
temu to każdemu oczy by wyskoczyły - chyba ktoś nie widział systemów eksperckich :)
Kokoniłaj
  • Rejestracja:około 7 lat
  • Ostatnio:około 2 godziny
  • Postów:182
1

Super. Jestem ciekawy czy poradzi sobie z dodaniem opcji rysowania prostokątów z gradientem liniowym jako wypełnieniem wraz z możliwością rotacji tego gradientu.

pradoslaw
Administrator
  • Rejestracja:około 8 lat
  • Ostatnio:minuta
  • Lokalizacja:Wrocław
  • Postów:92
3

@Kokoniłaj tak wygląda efekt jednego dodatkowego prompta:
Markup 2025-02-13 at 14.22.47.png

opiszon
  • Rejestracja:ponad 2 lata
  • Ostatnio:19 minut
  • Postów:779
13

Widzę zachwyt nad gradientami co powoduje że muszę zadać pytanie:

Czy to ai projektuje aktualny layout oraz pisze kod 4p?

edytowany 1x, ostatnio: opiszon
SZ
  • Rejestracja:około 14 lat
  • Ostatnio:około 2 godziny
  • Postów:178
1

A powiedz mu żeby dodał takiego painta do forum 4p, jako opcja dodania posta do forum. Że wybieram sobie opcje, czy chce odpowiedzieć tekstem, czy obrazkiem.

KM
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 4 godziny
  • Postów:99
5

OGŁASZAM KONIEC ELDORADOimage

obscurity
hej, znam tę scenę
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
1

Progres jest ogromny, ja jednak wyskoczyłem ponad promot o jakieś jednostronicowe toole i chciałem zrobić pełnoprawną aplikacje.
Założenie API w node.js, a na froncie sveltekit
API korzysta już z gotowej bazy danych.

Generowanie backendu bez napisania ani jednej linijki kodu 2 andpointy z get, wygenerował działające

Z front endem sobie nie poradził nie udało mi się stworzyć gotowego i działającego. Nie mam jednak złudzeń, że to kwestia czasu i będzie potrafił

obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około godziny
3

No jeszcze dwie minuty i by miał wszystkie funkcje gimpa. Ale sklonowanie repo zajmuje mniej. Jest w stanie zrobić coś co jeszcze nie istnieje?

Niech doda odpalanie kodu do postów na 4p i ponaprawia tu bugi.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 1x, ostatnio: obscurity
RequiredNickname
  • Rejestracja:prawie 5 lat
  • Ostatnio:9 minut
  • Postów:613
2

a teraz poproś go aby zrobił ficzer w twoim spaghetti kozie lub naprawił buga z produkcji 🙃

SZ
No my próbowaliśmy... z Copilot wersji enterprise. ... polegliśmy po 8h pisania promptów i ciągłej walce z czatem, niby pisał że coś poprawia, a jednak nie poprawił. No i nigdy to nie działało z frontem, tzn zawsze zwracał inaczej dane niż miał napisane w kontrakcie. Test robiony jakieś 2 miechy temu. Programista MID to samo robi w 2h...
loza_prowizoryczna
Kojot jest AI odporny. Do niego trza umysłu lżejszej kategorii.
FA
Problem z tymi narzędziami jest taki że one piszą co chcą napisać. Jeżeli dasz im coś mega specyficznego gdzie faktycznie trzeba myśleć a nie od gabinet pracę od kolei to raz zarazem polegają. Kod też nie jest kodem skalowalnym tylko spaghetti na poziomie juniora. I dopiszczenie wyników tak by jakość była na produkcję zabiera więcej wynislku niż oszczedzq
loza_prowizoryczna
Kod też nie jest kodem skalowalnym tylko spaghetti na poziomie juniora. - wychodzi na to że te devy co piszą syfski kod w syfskich językach okazali się najbardziej sprytnymi w systemie skalowalnego kapitalizmu.
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
2

Ja patrzę na to trochę inaczej, teraz Chińczycy wyszli z deepseek i mocno namieszali.
Wszyscy liczący się w branży AI nagle mocno przyspieszyli.
Mogę oczywiście punktować czego AI jeszcze nie potrafi, ale IMO to kwestia czasu. Trend jest nakreślony i zaczynają jak zawsze najwieksi: https://www.linkedin.com/posts/andy-jassy-8b1615_one-of-the-most-tedious-but-critical-tasks-activity-7232374162185461760-AdSz/?utm_source%3Dshare%26utm_medium%3Dmember_ios

Idą za tym tak ogromne pieniądze, są pierwsze efekty więc to nie pytanie czy? a kiedy? Możemy heheszkowac. Możemy też poważnie podejść do tematu i poobserwować jak to wpływa na inne branże.

Viralowa reklama VOLVO zrobiona w niecałe 24 godziny przez AI

https://m.youtube.com/watch?v=VYZrsEyiEFs

Gdzie eksperci szacują że budżet na jej wykonanie tradycyjnie to może dochodzić do 0,5 mln USD

Biznes to zauważa i liczy pieniądze.

Zobacz pozostałe 2 komentarze
PA
To że przyspiesza i modele stają się bardziej precyzyjne to jedno. Staje się to też coraż tańsze, a to tylko przyspieszy proces.
RequiredNickname
Z czym niby deepseek namieszał? Naopowiadali że skopiowali chatagpt za kilka baniek ale o tym że wcześniej kupili sprzętu za 500 milionów i są dotowani przez partie już nikt nie mówi xD
PA
Tym, że się pojawił, że weszła konkurencja która trochę zmienia układ sił na rynku. Nie łykam wszystkiego co podają bo to nie ma znaczenia... Ale spore poruszenie wśród aktualnuch liderów AI wprowadził.
RequiredNickname
Przecież konkurencja była już wcześniej np. claude. DeepSeek "namieszał" na rynku bo Chińczycy chwalili się że wytrenowali konkurencję za kilka milionów (i to łyknęły media) zapominając, że R&D swoje kosztuje, sprzęt swoje kosztuje i że Chińczycy najpewniej mocno czerpali z dorobku OpenAI.
PA
Różnica polega na tym że Chińczycy są po drugiej stronie oceanu...
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
0

@szok Fiimik z linkowanego posta nie odnosi się do opisywanego przypadku, ale patrząc na prompt:

screenshot-20250214100723.png

Gdzieś mi się kojarzy, że to włąsnie była jakas stara wersja JAVY, i musieli to upgradeować bo to uniemozliwiało im rozwój.

opiszon
A ten q pod spodem używa recept z openrewrite pewnie ;-)
SZ
@opiszon: Odpowiedź z GPT: Tak, Amazon Q w opcji /transform korzysta z OpenRewrite. Amazon Q Code Transformation wykorzystuje części OpenRewrite, aby przyspieszyć aktualizacje języka Java dla klientów. AWS planuje również wnosić wkład do społeczności OpenRewrite, udostępniając opracowane w ramach Amazon Q Code Transformation receptury jako open source. AWS.AMAZON.COM
opiszon
Receptę z openrewrite też mogę sam zaaplikować oszczedzajac czas. Czekam na jakiś prawdziwy przypadek gdzie rzeczywiście ai zmigruje kod. Bo aplikacja recepty z openrewrite nie zmigruje ci każdej apki.
Manna5
  • Rejestracja:prawie 6 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Kraków
  • Postów:635
0
pradoslaw napisał(a):

Zero bugów.

Na pewno? Testowałeś różne nietypowe sytuacje?


obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około godziny
1
Manna5 napisał(a):
pradoslaw napisał(a):

Zero bugów.

Na pewno? Testowałeś różne nietypowe sytuacje?

Przeglądałem kod i nie znalazłem nic oczywistego, ale na przykład historia modyfikacji jest przechowywana na bogato - każde kliknięcie to snapshot całego canvasa do pamięci co zwiększa zużycie pamięci o 2MB. Kilkanaście sekund zabawy i zakładka wykorzystuje już 250MB pamięci.
Nie ma limitu cofania co oznacza że w pewnym momencie mogą się pojawić problemy z pamięcią.

Oczywiście to jest do poprawienia przez AI, ale trzeba to przetestować i wpaść na to samemu i wiedzieć o co zapytać. Ciekawe kiedy AI będzie w stanie myśleć o wszystkich edge case'ach.

Panczo napisał(a):

Viralowa reklama VOLVO zrobiona w niecałe 24 godziny przez AI

https://m.youtube.com/watch?v=VYZrsEyiEFs

Gdzie eksperci szacują że budżet na jej wykonanie tradycyjnie to może dochodzić do 0,5 mln USD

Biznes to zauważa i liczy pieniądze.

Niestety to głównie oznacza większą ilość shitu w necie, już teraz co 20 materiał na jaki trafiam jest wygenerowany przez AI, w sklepach pojawiają się obrazy i książki wygenerowane przez AI. Niedługo utoniemy w shit contencie, mało kto będzie chciał się uczyć robić tego wszystkiego skoro lata mu zajmie dojście do poziomu AI a potem miesiące mu zajmie zrobienie coś co AI robi w sekundę więc umiejętności zaczną zanikać.
Idiocracy ziści się dużo szybciej niż przewidywano.

Nie cieszy mnie rozwój AI nie tylko dlatego że zagraża mojej pracy i sprawi że moje hobby będzie jałowe i mało ekscytujące, ale głównie dlatego że nie umiem sobie wyobrazić jednego scenariusza w którym wynalezienie AGI skończy się dobrze dla ludzkości.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
1

@obscurity nie jestem idealistą i nie patrzę na AI bezkrytycznie, tyle ile problemów rozwiąże to pewnie tyle samo stworzy.
Sam osobiście jestem "przerażony" że już teraz dostaje kompentecje których nie byłbym wstanie opanować samemu, jak choćby tworzenie grafik, nie ma w tym kierunku żadnego talentu, a tak bez problemu jestem wstanie to zrobić.

Nie patrzę na to w kategoriach emocji, to czy AGI faktycznie powstanie jest pytaniem otwartym, ale to, że w niedalekiej przyszłości programiści będą zastępowani przez AI wydaje mi się całkiem realne. Nie że nie będą potrzebni, ale będzie ich potrzeba zwyczajnie mniej. To oczywiście mój punkt widzenia, ale wynika z doniesień prasowych o tym co robią najwięksi gracze. Już choćby to że MS "daje" copilota za darmo odczytuje jako krok w kierunku zastapienia programistów. W końcu dane z internetu "się skończyły", to bedą analizować kody użytkowników.

Dlatego nie patrzę na AI na miejsce w którym jest teraz, a na to gdzie może być.

Rozmawiam też z właścicielami firm i Ci którzy poszli w AI notują wzrosty w swoich biznesach, szczególnie agencje marketingowe. Jeden własciciel mi podał swój case: pracownik pewną rzecz (nie napiszę jaką, bo szczerze zapomniałem, a nie jestem marketingowcem więc nie chcę się wygłupić) robił od 4-5 dni i klient za to płacił 6k. Dzięki AI robi dokładnie to samo w niecałą godzinę...

Moi klienci również pytają kiedy wprowadzę AI w swoich produktach. I sam mocno ogarniam temat. Z mojego podwórka (a raczej mojej spółki) chce wprowadzić nowy produkt i wyszło mi że potrzebuję do tego 2 programistów, no i liczę: uprośćmy że na tą 2 wydam 50k miesięcznie co rocznie daje 600k, to zastanawiam się, czy nie wyposażyć mój zespół w AI do wspomagania/generowania kodu i zapłacić za to AI niech będzie 100k rocznie, ale ogarnę to tymi samymi zasobami którymi dysponuje. I wiem, że nie jestem odosobniony w takim myśleniu.

Teraz pozostaje pytanie, czy negujemy AI w biznesie, czy wsiadamy do tego pociągu.

pradoslaw
"Dlatego nie patrzę na AI na miejsce w którym jest teraz, a na to gdzie może być." <3
PA
@pradoslaw: aż musiałem dzieci spytać co znaczy ten emotikon 🤣
MA
Daj znać jak poszło z tym AI zamiast programistów
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około godziny
2
Panczo napisał(a):

pracownik pewną rzecz (nie napiszę jaką, bo szczerze zapomniałem, a nie jestem marketingowcem więc nie chcę się wygłupić) robił od 4-5 dni i klient za to płacił 6k. Dzięki AI robi dokładnie to samo w niecałą godzinę...

no to pięknie, tylko że teraz moim zdaniem mamy złoty czas w którym mamy możliwość wykonania czegoś szybko przy użyciu AI a skasowania jak za pracę ręczną. Te czasy się szybko skończą i niedługo klienci odkryją że mogą sobie to sami zrobić w godzinę, lub konkurencyjność sprowadzi to do stawki godzinowej.
Nikt nie będzie płacić na ms painta gotowego w 19s tyle samo co za podobny projekt napisany ręcznie. To raczej nie będzie tak że małe firmy będą nagle w stanie konkurować z gigantami tylko skala skomplikowania wszystkiego się znacznie zwiększy żeby zarobić tyle samo.
Skoro w godzinę za parę dolarów można teraz stworzyć reklamę wartą 0,5 mln USD to wszyscy mogą zrobić to samo i ta reklama już nie jest warta 0,5 mln USD a żeby się wybić niedługo będzie potrzeba czegoś znacznie lepszego bo tego typu reklamy niedługo będą robić podobne wrażenie jak te na regionalnych tvp.
Prezentacje w powerpoincie też kiedyś robiły duże wrażenie.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 1x, ostatnio: obscurity
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
1

Masz rację, na razie porównujemy wytwory AI do tradycyjnej pracy i stąd się biorą te rozbieżności w cenach. I to się skończy, jak AI się upowszechni. Ja patrze na przyszłość swojego biznesu i błędem byłoby ignorować to co się wokół AI obecnie dzieje. Nie jestem programistą na etacie, tylko patrzę czy przetrwam na rynku w zmieniającym sie otoczeniu. Teraz jest właśnie odpowiedni moment aby podejmować strategiczne decyzje.

WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:około 22 godziny
  • Postów:5105
1

@Panczo

To oczywiście mój punkt widzenia, ale wynika z doniesień prasowych o tym co robią najwięksi gracze

Doniesienia prasowe są nierzadko g**no warte, im dłużej inwestuje, im dłużej interesuje się daną branżą, im dłużej czytam sprawozdania firm, im dłużej śledze opinie pracowników danych firm itd. itd.,
to coraz bardziej widzę że większość newsów jest g**no warta, a w szczególności te, publikowane przez polskie outlety.

Cykl g**no-newsa:

  1. Plotka na twitterze wynikająca z niepoprawnej interpretacji czegoś lub niezrozumienia branży
  2. Artykuł w amerykańskim plotku na podstawie twittera
  3. Artykuł jest linkowany na twitterach/redditach
  4. Inne amerykańskie outlety piszą podobny artykuł jedynie modyfikując go minimalnie
  5. Polskie outlety robią copy+paste w translator i publikują to samo
  6. Za miesiąc okazuje się że to bajka :D
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 13 godzin
  • Postów:3861
0

@WeiXiao zatem któryś z nas się myli. Ja tu reprezentuję tylko i wyłącznie swoje opinie/przemyślenia. Jak masz inne to ok.

edytowany 1x, ostatnio: Panczo
HA
  • Rejestracja:około 6 lat
  • Ostatnio:około 4 godziny
  • Postów:1005
0

Staram się podchodzić do AI raczej sceptycznie. Nie sądzę, że w ciągu 2-3 lat nam zabierze prace, ale fakt, że postęp robi wrażenie.

Mnie zupełnie nie ruszają przykłady takiej jak tutaj podany, bo napisanie "jakiejść" aplikacji od zera to relatywnie prosty temat. Natomiast robi na mnie ogromne wrażenie, jak AI potrafi wyciągnąć informacje z projektu i na ich podstawie ulepić proste kawałki kodu, które mają sens - szczególnie gdy chodzi o customowy kod, a nie jakieś generyczne bebechy frameworka. Ostatnio miałem już kilka takich zdziwień, gdzie całkiem nietrywialne rzeczy potrafił sensownie zrobić. Daleko jeszcze do pisania biznesowego kodu w rozbudowanej aplikacji, ale przy umiejętnym użyciu mocno przyspiesza pracę. Wygląda na to, że w najbliższych latach będzie mocny shift z programistów na osoby ze skilem biznesowym. Najgorzej chyba będę miały osoby, które zajmują się programowaniem, ale nie wyszły na wysoki level i nie mają zdolności biznesowy/miękkich. Dla nich AI to powoli bezpośrednia konkurencja co już teraz widać po rynku juniorski. Po co mi junior, jak AI zrobi to samo szybciej.

crestfallen
  • Rejestracja:3 miesiące
  • Ostatnio:około 3 godziny
  • Postów:36
1

Super, taki program napisze i 12latek. Dodajmy więc funkcjonalności które uchodzą za trudne w implementacji:

  • Zoom z możliwością rysowania przy powiększeniu
  • Dodawanie tekstu na obrazek (połączone z zoom'em zaczyna być ciekawe)
  • Zaznaczanie i wycinanie nieprostokątnych obszarów obrazu (lasso)

Mogę się założyć o pierwszej klasy 100 bitów i 2 bajty że AI się zakrztusi i wypluje jakieś farmazony...

edytowany 1x, ostatnio: crestfallen
pradoslaw
@crestfallen: i już możesz przekonać się jak to działa.
obscurity
te funkcje też pisałem jak miałem 12 lat, co prawda nie zajeło mi to kilkanaście sekund ale to nie są trudne do implementacji ani odkrywcze ficzery
pradoslaw
Administrator
  • Rejestracja:około 8 lat
  • Ostatnio:minuta
  • Lokalizacja:Wrocław
  • Postów:92
1
crestfallen napisał(a):

Super, taki program napisze i 12latek. Dodajmy więc funkcjonalności które uchodzą za trudne w implementacji:

  • Zoom z możliwością rysowania przy powiększeniu
  • Dodawanie tekstu na obrazek (połączone z zoom'em zaczyna być ciekawe)
  • Zaznaczanie i wycinanie nieprostokątnych obszarów obrazu (lasso)

Mogę się założyć o pierwszej klasy 100 bitów i 2 bajty że AI się zakrztusi i wypluje jakieś farmazony...

Krótki opis nowych funkcji
Zoom: Suwak „Zoom” (50–300%) powiększa lub zmniejsza widok obu warstw (główny i tymczasowy). Funkcja getMousePos uwzględnia aktualny współczynnik powiększenia, dzięki czemu rysowanie działa poprawnie przy dowolnym zoomie.
Tekst: Po wybraniu narzędzia „Tekst” i kliknięciu w obszarze płótna pojawia się pole edycji. Po wpisaniu tekstu i naciśnięciu Enter, tekst jest rysowany na głównym canvasie.
Lasso: Po wybraniu narzędzia „Lasso” użytkownik może rysować nieregularną ścieżkę – podgląd zaznaczenia rysowany jest na czerwono. Po zakończeniu zaznaczania pojawia się komunikat potwierdzający wycięcie zaznaczenia – jeżeli użytkownik zatwierdzi, obszar wewnątrz lasso zostanie usunięty z obrazu (wycięty).

Miłego korzystania z aplikacji!

Kopiuj
<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8" />
  <title>Advanced MS Paint – 4programmers.net UI z Zoom, Tekstem i Lasso</title>
  <style>
    :root {
      --primary: #005792;       /* Niebieski inspirowany 4programmers.net */
      --secondary: #ffffff;
      --text: #ffffff;
      --background: #f5f5f5;
      --button-hover: #007ac1;
    }
    body {
      margin: 0;
      font-family: Arial, sans-serif;
      background-color: var(--background);
    }
    #toolbar {
      background-color: var(--primary);
      padding: 10px;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      color: var(--text);
    }
    #toolbar label {
      margin-right: 5px;
    }
    #toolbar > * {
      margin: 5px;
    }
    #toolbar input[type="range"] {
      vertical-align: middle;
    }
    #toolbar input[type="color"] {
      vertical-align: middle;
      border: none;
      padding: 0;
      width: 40px;
      height: 30px;
      background: var(--secondary);
      cursor: pointer;
    }
    #toolbar select {
      background: var(--secondary);
      color: #000;
      border: none;
      padding: 5px;
      border-radius: 3px;
      cursor: pointer;
    }
    #toolbar button {
      background: var(--secondary);
      color: var(--primary);
      border: none;
      padding: 8px 12px;
      border-radius: 3px;
      cursor: pointer;
      transition: background 0.3s;
    }
    #toolbar button:hover {
      background: var(--button-hover);
      color: var(--secondary);
    }
    /* Kontener płótna – ustalamy overflow:hidden, by transformacje nie powodowały niechcianych pasków */
    #canvasContainer {
      position: relative;
      border: 1px solid #ccc;
      margin: 10px auto;
      background-color: var(--secondary);
      width: 800px;
      height: 600px;
      overflow: hidden;
    }
    canvas {
      position: absolute;
      left: 0;
      top: 0;
      transform-origin: top left;
    }
  </style>
</head>
<body>
  <div id="toolbar">
    <label for="tool">Narzędzie:</label>
    <select id="tool">
      <option value="pencil">Ołówek</option>
      <option value="line">Linia</option>
      <option value="rectangle">Prostokąt</option>
      <option value="circle">Koło</option>
      <option value="eraser">Gumka</option>
      <option value="text">Tekst</option>
      <option value="lasso">Lasso</option>
    </select>

    <label for="brushSize">Grubość pędzla:</label>
    <input type="range" id="brushSize" min="1" max="50" value="5" />

    <label for="strokeColor">Kolor konturu:</label>
    <input type="color" id="strokeColor" value="#000000" />

    <label for="fillColor">Kolor wypełnienia:</label>
    <input type="color" id="fillColor" value="#000000" />

    <label for="fillShape">Wypełnienie:</label>
    <input type="checkbox" id="fillShape" />

    <label for="gradientFill">Wypełnienie gradientem:</label>
    <input type="checkbox" id="gradientFill" />

    <label for="gradientRotation">Rotacja gradientu (°):</label>
    <input type="range" id="gradientRotation" min="0" max="360" value="0" />

    <label for="zoomSlider">Zoom:</label>
    <input type="range" id="zoomSlider" min="50" max="300" value="100" />
    <span id="zoomValue">100%</span>

    <button id="clearCanvas">Wyczyść</button>
    <button id="saveCanvas">Zapisz</button>
    <button id="undo">Cofnij</button>
    <button id="redo">Wróć</button>
  </div>

  <div id="canvasContainer">
    <canvas id="canvas" width="800" height="600"></canvas>
    <canvas id="tempCanvas" width="800" height="600"></canvas>
  </div>

  <script>
    // Pobierz elementy i konteksty
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    const tempCanvas = document.getElementById('tempCanvas');
    const tempCtx = tempCanvas.getContext('2d');

    const canvasContainer = document.getElementById('canvasContainer');

    const toolSelect = document.getElementById('tool');
    const brushSize = document.getElementById('brushSize');
    const strokeColor = document.getElementById('strokeColor');
    const fillColor = document.getElementById('fillColor');
    const fillShape = document.getElementById('fillShape');
    const gradientFill = document.getElementById('gradientFill');
    const gradientRotation = document.getElementById('gradientRotation');
    const zoomSlider = document.getElementById('zoomSlider');
    const zoomValue = document.getElementById('zoomValue');
    const clearCanvasBtn = document.getElementById('clearCanvas');
    const saveCanvasBtn = document.getElementById('saveCanvas');
    const undoBtn = document.getElementById('undo');
    const redoBtn = document.getElementById('redo');

    let drawing = false;
    let currentTool = toolSelect.value;
    let startX = 0, startY = 0;
    let currentZoom = zoomSlider.value / 100;

    // Do obsługi narzędzia Lasso – zbiór punktów
    let lassoPoints = [];

    // Stosy do cofania i ponawiania zmian
    let undoStack = [];
    let redoStack = [];

    // Zapisz aktualny stan płótna
    function pushState() {
      redoStack = [];
      undoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
    }

    function undo() {
      if (undoStack.length > 0) {
        redoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
        const state = undoStack.pop();
        ctx.putImageData(state, 0, 0);
      }
    }

    function redo() {
      if (redoStack.length > 0) {
        undoStack.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
        const state = redoStack.pop();
        ctx.putImageData(state, 0, 0);
      }
    }

    // Inicjalizacja – zapis pustego płótna
    pushState();

    // Aktualizacja wybranego narzędzia
    toolSelect.addEventListener('change', function () {
      currentTool = this.value;
    });

    // Obsługa zoomu – zmiana wartości zoom i transformacja canvasów
    zoomSlider.addEventListener('input', function() {
      currentZoom = zoomSlider.value / 100;
      zoomValue.textContent = zoomSlider.value + '%';
      canvas.style.transform = `scale(${currentZoom})`;
      tempCanvas.style.transform = `scale(${currentZoom})`;
    });

    // Funkcja pobierająca pozycję myszy – uwzględnia skalowanie
    function getMousePos(e) {
      const rect = tempCanvas.getBoundingClientRect();
      return {
        x: (e.clientX - rect.left) / currentZoom,
        y: (e.clientY - rect.top) / currentZoom
      };
    }

    // Obsługa zdarzeń myszy na canvasie tymczasowym
    tempCanvas.addEventListener('mousedown', startDrawing);
    tempCanvas.addEventListener('mousemove', draw);
    tempCanvas.addEventListener('mouseup', finishDrawing);
    tempCanvas.addEventListener('mouseout', finishDrawing);

    function startDrawing(e) {
      const pos = getMousePos(e);
      startX = pos.x;
      startY = pos.y;

      // Narzędzie Tekst – tworzymy pole input w miejscu kliknięcia
      if (currentTool === 'text') {
        let input = document.createElement("input");
        input.type = "text";
        input.style.position = "absolute";
        // Pozycjonowanie względem kontenera (używamy współrzędnych z eventu)
        const containerRect = canvasContainer.getBoundingClientRect();
        input.style.left = (e.clientX - containerRect.left) + "px";
        input.style.top = (e.clientY - containerRect.top) + "px";
        input.style.fontSize = (brushSize.value * currentZoom) + "px";
        input.style.border = "1px solid #000";
        canvasContainer.appendChild(input);
        input.focus();
        input.addEventListener("keydown", function(event) {
          if (event.key === "Enter") {
            let text = input.value;
            ctx.font = `${brushSize.value}px Arial`;
            ctx.fillStyle = fillColor.value;
            ctx.fillText(text, startX, startY);
            canvasContainer.removeChild(input);
            pushState();
          }
        });
        return;
      }

      // Narzędzie Lasso – inicjujemy zbiór punktów
      if (currentTool === 'lasso') {
        lassoPoints = [];
        lassoPoints.push({x: pos.x, y: pos.y});
        drawing = true;
        return;
      }

      drawing = true;
      // Dla ołówka i gumki – rozpoczynamy ścieżkę
      if (currentTool === 'pencil' || currentTool === 'eraser') {
        ctx.beginPath();
        ctx.moveTo(startX, startY);
      }
    }

    function draw(e) {
      if (!drawing) return;
      const pos = getMousePos(e);
      const mouseX = pos.x;
      const mouseY = pos.y;

      if (currentTool === 'pencil') {
        ctx.lineTo(mouseX, mouseY);
        ctx.strokeStyle = strokeColor.value;
        ctx.lineWidth = brushSize.value;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        ctx.stroke();
      } else if (currentTool === 'eraser') {
        ctx.globalCompositeOperation = 'destination-out';
        ctx.lineTo(mouseX, mouseY);
        ctx.strokeStyle = 'rgba(0,0,0,1)';
        ctx.lineWidth = brushSize.value;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        ctx.stroke();
        ctx.globalCompositeOperation = 'source-over';
      } else if (currentTool === 'line') {
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        tempCtx.lineWidth = brushSize.value;
        tempCtx.strokeStyle = strokeColor.value;
        tempCtx.lineCap = 'round';
        tempCtx.beginPath();
        tempCtx.moveTo(startX, startY);
        tempCtx.lineTo(mouseX, mouseY);
        tempCtx.stroke();
      } else if (currentTool === 'rectangle') {
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        tempCtx.lineWidth = brushSize.value;
        tempCtx.strokeStyle = strokeColor.value;
        tempCtx.fillStyle = fillColor.value;
        if (fillShape.checked) {
          if (gradientFill.checked) {
            let width = mouseX - startX;
            let height = mouseY - startY;
            let cx = startX + width / 2;
            let cy = startY + height / 2;
            let halfDiagonal = Math.sqrt(width * width + height * height) / 2;
            let angle = gradientRotation.value * Math.PI / 180;
            let x0 = cx - halfDiagonal * Math.cos(angle);
            let y0 = cy - halfDiagonal * Math.sin(angle);
            let x1 = cx + halfDiagonal * Math.cos(angle);
            let y1 = cy + halfDiagonal * Math.sin(angle);
            let grad = tempCtx.createLinearGradient(x0, y0, x1, y1);
            grad.addColorStop(0, fillColor.value);
            grad.addColorStop(1, strokeColor.value);
            tempCtx.fillStyle = grad;
            tempCtx.fillRect(startX, startY, width, height);
          } else {
            tempCtx.fillRect(startX, startY, mouseX - startX, mouseY - startY);
          }
        }
        tempCtx.strokeRect(startX, startY, mouseX - startX, mouseY - startY);
      } else if (currentTool === 'circle') {
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        let radius = Math.sqrt(Math.pow(mouseX - startX, 2) + Math.pow(mouseY - startY, 2));
        tempCtx.lineWidth = brushSize.value;
        tempCtx.strokeStyle = strokeColor.value;
        tempCtx.beginPath();
        tempCtx.arc(startX, startY, radius, 0, Math.PI * 2);
        if (fillShape.checked) {
          tempCtx.fillStyle = fillColor.value;
          tempCtx.fill();
        }
        tempCtx.stroke();
      } else if (currentTool === 'lasso') {
        // Dodajemy punkty do ścieżki lasso i rysujemy podgląd
        lassoPoints.push({x: mouseX, y: mouseY});
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        tempCtx.beginPath();
        tempCtx.moveTo(lassoPoints[0].x, lassoPoints[0].y);
        for (let i = 1; i < lassoPoints.length; i++) {
          tempCtx.lineTo(lassoPoints[i].x, lassoPoints[i].y);
        }
        tempCtx.strokeStyle = 'red';
        tempCtx.lineWidth = 1;
        tempCtx.stroke();
      }
    }

    function finishDrawing(e) {
      if (!drawing) return;
      const pos = getMousePos(e);
      const mouseX = pos.x;
      const mouseY = pos.y;

      if (currentTool === 'pencil' || currentTool === 'eraser') {
        // Dla tych narzędzi kończymy ścieżkę bez dodatkowych operacji
      } else if (currentTool === 'line') {
        ctx.lineWidth = brushSize.value;
        ctx.strokeStyle = strokeColor.value;
        ctx.lineCap = 'round';
        ctx.beginPath();
        ctx.moveTo(startX, startY);
        ctx.lineTo(mouseX, mouseY);
        ctx.stroke();
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
      } else if (currentTool === 'rectangle') {
        ctx.lineWidth = brushSize.value;
        ctx.strokeStyle = strokeColor.value;
        if (fillShape.checked) {
          if (gradientFill.checked) {
            let width = mouseX - startX;
            let height = mouseY - startY;
            let cx = startX + width / 2;
            let cy = startY + height / 2;
            let halfDiagonal = Math.sqrt(width * width + height * height) / 2;
            let angle = gradientRotation.value * Math.PI / 180;
            let x0 = cx - halfDiagonal * Math.cos(angle);
            let y0 = cy - halfDiagonal * Math.sin(angle);
            let x1 = cx + halfDiagonal * Math.cos(angle);
            let y1 = cy + halfDiagonal * Math.sin(angle);
            let grad = ctx.createLinearGradient(x0, y0, x1, y1);
            grad.addColorStop(0, fillColor.value);
            grad.addColorStop(1, strokeColor.value);
            ctx.fillStyle = grad;
            ctx.fillRect(startX, startY, mouseX - startX, mouseY - startY);
          } else {
            ctx.fillStyle = fillColor.value;
            ctx.fillRect(startX, startY, mouseX - startX, mouseY - startY);
          }
        }
        ctx.strokeRect(startX, startY, mouseX - startX, mouseY - startY);
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
      } else if (currentTool === 'circle') {
        let radius = Math.sqrt(Math.pow(mouseX - startX, 2) + Math.pow(mouseY - startY, 2));
        ctx.lineWidth = brushSize.value;
        ctx.strokeStyle = strokeColor.value;
        ctx.beginPath();
        ctx.arc(startX, startY, radius, 0, Math.PI * 2);
        if (fillShape.checked) {
          ctx.fillStyle = fillColor.value;
          ctx.fill();
        }
        ctx.stroke();
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
      } else if (currentTool === 'lasso') {
        // Kończymy zaznaczanie – rysujemy zamkniętą ścieżkę
        drawing = false;
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        tempCtx.beginPath();
        tempCtx.moveTo(lassoPoints[0].x, lassoPoints[0].y);
        for (let i = 1; i < lassoPoints.length; i++) {
          tempCtx.lineTo(lassoPoints[i].x, lassoPoints[i].y);
        }
        tempCtx.closePath();
        tempCtx.strokeStyle = 'red';
        tempCtx.lineWidth = 1;
        tempCtx.stroke();
        // Zapytaj użytkownika, czy wyciąć zaznaczony obszar
        if (confirm("Wyciąć zaznaczenie?")) {
          ctx.save();
          ctx.beginPath();
          ctx.moveTo(lassoPoints[0].x, lassoPoints[0].y);
          for (let i = 1; i < lassoPoints.length; i++) {
            ctx.lineTo(lassoPoints[i].x, lassoPoints[i].y);
          }
          ctx.closePath();
          ctx.clip();
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          ctx.restore();
          pushState();
        }
        tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
        lassoPoints = [];
        return;
      }
      drawing = false;
      pushState();
    }

    clearCanvasBtn.addEventListener('click', function () {
      pushState();
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      pushState();
    });

    saveCanvasBtn.addEventListener('click', function () {
      const mergedCanvas = document.createElement('canvas');
      mergedCanvas.width = canvas.width;
      mergedCanvas.height = canvas.height;
      const mergedCtx = mergedCanvas.getContext('2d');
      mergedCtx.drawImage(canvas, 0, 0);
      mergedCtx.drawImage(tempCanvas, 0, 0);
      const link = document.createElement('a');
      link.download = 'my_painting.png';
      link.href = mergedCanvas.toDataURL();
      link.click();
    });

    undoBtn.addEventListener('click', undo);
    redoBtn.addEventListener('click', redo);
  </script>
</body>
</html>


HA
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 6 godzin
  • Postów:69
4

@pradoslaw rysowanie na zoomie działa spoko, natomiast pole tekstowe jest przyklejone na stałe. Dodaj sobie tekst i potem zrób zoom - tekst zostanie w tym samym miejscu i będzie miał taki sam rozmiar. Teraz z zoomem dodaj pole tekstowe - będzie dużo większe i zostanie takich samych rozmiarów gdy zooma zresetujesz. Do tego nie da się rysować po tekście. Wycinanie tekstu lassem nie działa.

Sam bawiłem się ostatnio zestawem Cursor + Composer i faktycznie jest w stanie mega szybko zakodzić coś działającego, ale dopieszczanie szczegółów wręcz graniczy z cudem, a czasem musiałem i tak mu dawać konkretne, techniczne instrukcje - np. wymiękał, gdy kazałem mu zrobić prosty layout z 3 kolumnami, gdzie środkowa jest rozepchana względem treści, a boczne dzielą się pozostałym miejscem po równo, a kontent w każdej kolumnie jest wyśrodkowany. Ogarnął dopiero jak mu kazałem zrobić flexboksa o konkretnych parametrach.

edytowany 1x, ostatnio: hawus
pradoslaw
Próbowałem poprawić, by nie było problemów o których napisałeś. Natomiast teraz jedną rzecz naprawia, a inną psuje. ;)
HA
No to mamy podobne doświadczenia :) do pewnoego momentu jest super, ale w pewnym momencie AI wymięka i trzeba albo je prowadzić za rączkę, albo samemu coś naklepać.
RE
nie piszę w js ale mam takie wrażenie że ten kod jest po prostu długi. Z doświadczeń z copilot. wiem że potrafi generować długie kody, zagnieżdżenia i często najmniejsza linią oporu tzn. nie używa np. STL tylko jedzie ręcznie po elementach itp. Trzeba wtedy uszczegółowić mu pewne rzeczy albo smemu siąść. A w Rust i fltk jak chciałem coś nakodzić to się zapętlał dosłownie w odpowiedziach a w tym kodzie coś zrozumiec to cóż... Boost do produktywności i tyle.
obscurity
@pradoslaw: czyli dokładnie to samo co za czasów gpt 3.5, dobre do bootstrapowania aplikacji ale im dalej w las tym ciemniej
crestfallen
  • Rejestracja:3 miesiące
  • Ostatnio:około 3 godziny
  • Postów:36
1

Zoom+Tekst - porażka.
Lasso - działa lepiej niż myślałem.

Jak zawsze problem jest w szczegółach - gdy myślałem o dodawaniu tekstu to liczyłem na dialog box z wyborem czcionki, krojów pisma, cieniem.

Powiem tak lepiej niż myślałem, to już nie 12 latek ale słaby student pierwszego roku IT!

obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około godziny
0
pradoslaw napisał(a):

Miłego korzystania z aplikacji!

byłoby miło gdybyśmy nie musieli tego przeklejać do pliku żeby uruchomić. Może poprosisz chat żeby dopisał tu opcję odpalania snippetów HTML/CSS/JS wewnątrz strony tak jak na stackoverflow


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około godziny
1
crestfallen napisał(a):

Lasso - działa lepiej niż myślałem.

No cóż, nie ma tu nic trudnego, po prostu zamalowuje ścieżkę z punktów

Kopiuj
if (confirm("Wyciąć zaznaczenie?")) {
          ctx.save();
          ctx.beginPath();
          ctx.moveTo(lassoPoints[0].x, lassoPoints[0].y);
          for (let i = 1; i < lassoPoints.length; i++) {
            ctx.lineTo(lassoPoints[i].x, lassoPoints[i].y);
          }
          ctx.closePath();
          ctx.clip();

nie ma tu żadnego algorytmu który musi znaleźć elementy czy piksele w środku, to wszystko już jest wbudowane w canvas api. Przesuwanie byłoby już chyba trudniejsze.

To polećmy może już po całości, niech doda warstwy, elementy wektorowe z możliwością rasteryzacji i zaznaczanie lassem tych elementów, przesuwanie i zmiana rozmiarów tych elementów.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 2x, ostatnio: obscurity
Spine
  • Rejestracja:prawie 22 lata
  • Ostatnio:3 minuty
  • Postów:6613
0

@pradoslaw: Gratulacje!
Twoja pierwsza apka?


🕹️⌨️🖥️🖱️🎮
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)