oneshotlm
Compare all models on this prompt →

Matrix digital rain · gemma-4-31b-it

Create the Matrix digital rain effect on a full-screen black canvas: columns of falling green katakana glyphs with a trailing fade and a brighter leading character.

⛨ sandboxed Open in new tab ↗
transcript · 4 messages
user

Create the Matrix digital rain effect on a full-screen black canvas: columns of falling green katakana glyphs with a trailing fade and a brighter leading character.

assistant
thinking
The user wants a single-page web app (index.html) that implements the "Matrix digital rain" effect.
Requirements:
- Full-screen black canvas.
- Falling green katakana glyphs.
- Columns of falling characters.
- Trailing fade effect.
- Brighter leading character.
- Single self-contained `index.html` (CSS in `<style>`, JS in `<script>`).
- No external resources/CDNs.

Plan:
1.  Set up basic HTML structure.
2.  Add CSS to make the canvas full-screen and remove margins/padding.
3.  Implement JavaScript:
    - Initialize canvas and context.
    - Define the characters (katakana and some numbers/symbols).
    - Manage columns: track the current Y position for each column.
    - Animation loop:
        - Draw a semi-transparent black rectangle over the previous frame to create the fade effect.
        - For each column:
            - Pick a random character.
            - Draw the leading character in a brighter green (or white).
            - Draw the trailing characters in the classic matrix green.
            - Increment the Y position.
            - Reset Y position to a random negative value when it goes off-screen or randomly.

Character set for Matrix:
The Matrix uses Katakana. I'll include a set of Katakana characters.
Katakana range: `\u30A0` to `\u30FF`.

Let's refine the "leading character" part.
The standard Matrix rain has a white/bright green head and a green tail.
Since I'm drawing the fade by filling the whole screen with a semi-transparent black, the "tail" is naturally created by previous frames.
However, to specifically make the *leading* character brighter, I should draw the character at the current position with a different color, and let the fade handle the rest.
Wait, if I draw the head in white and the body in green, but I'm using `fillRect` with transparency for the fade, the characters already on the screen will fade.
Actually, the typical way is:
1. Fill screen with `rgba(0, 0, 0, 0.05)` to fade everything.
2. For each column:
   - Draw a character at `y` with green color.
   - (Optional) Draw a character at `y` with white color for the head, then immediately draw the green one? No, just draw the head in white and the ones before it were already drawn in green.
   - But wait, the "trailing fade" is handled by the `fillRect` overlay.
   - If I only draw the character at the current `y` in white, and the ones above it were green, they will fade.

Let's refine the loop:
1. `ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; ctx.fillRect(0, 0, width, height);`
2. For each column `i`:
   - `char = randomChar()`
   - `ctx.fillStyle = '#0F0';` (Green)
   - `ctx.fillText(char, x, y);`
   - `ctx.fillStyle = '#FFF';` (White/Bright)
   - `ctx.fillText(char, x, y);` (Wait, if I draw white on top of green, it's white. But the *next* frame it will be faded).
   - Actually, a better way to get a bright head:
     Draw the character at `y` in white.
     The characters that were at `y` in previous frames are now at `y-fontSize` etc.
     The `fillRect` fade will turn the white into green-ish if I'm not careful, or just fade it to black.
     To get the "green rain with white head":
     - The characters we draw in each frame are the ones *currently* falling.
     - If I draw the character at `y` in white, it's the head.
     - If I want a green trail, I need to draw the characters in green.
     - But I only draw *one* character per column per frame.
     - So if I draw it in white, the trail is white.
     - If I draw it in green, the trail is green.

Actually, the classic effect:
The head is white, the body is green.
Since we only draw the "new" character at the current position in each frame:
If we want the trail to be green, we must draw the character in green.
But the character we just drew is the head.
So:
1. Draw the character at `y` in white.
2. In the next frame, that character is now at `y-fontSize`. The `fillRect` fades it.
3. To make it green, we could draw it in white, and then in the next frame it's already faded.
Actually, many implementations do:
- Draw the character at `y` in white.
- Then immediately draw it (or slightly offset) in green? No.
- The trick is often:
  - Draw the character at `y` in white.
  - Then, in the *same* frame, draw the character at `y - fontSize` in green? No, because `y-fontSize` was already drawn in the previous frame.

Let's try this:
- Fill with `rgba(0, 0, 0, 0.05)`.
- For each column:
  - `ctx.fillStyle = '#0F0';`
  - `ctx.fillText(char, x, y);`
  - `ctx.fillStyle = '#FFF';`
  - `ctx.fillText(char, x, y);` // This makes the head white.
  - Now, as the head moves to `y + fontSize`, the previous white char is now at `y`. The `rgba(0,0,0,0.05)` makes it slightly darker. But it stays white-ish.
  - To make it green, we need the characters to be green.
  - Maybe:
    - `ctx.fillStyle = '#0F0';`
    - `ctx.fillText(char, x, y);`
    - `ctx.fillStyle = '#FFF';`
    - `ctx.fillText(char, x, y);`
    - Then in the next frame, it's faded.
    - Actually, the easiest way to get a white head and green tail:
      1. Draw the character at `y` in white.
      2. The fade makes it fade to black.
      3. To make it fade through green, we need the characters to be green.
      4. If we draw the character at `y` in white, and the character at `y - fontSize` in green? But we only draw one character per frame.

Correct approach for Matrix Rain:
1. Set `globalCompositeOperation` or just use the alpha fill.
2. For each column:
   - Draw char at `y` in white.
   - Now it's white.
   - Next frame: `fillRect(0,0,w,h, 0.05)` fades it.
   - To make it green, we can't just use `fillRect`.
   - Instead:
     - Draw char at `y` in white.
     - Draw char at `y - fontSize` in green?
     - No, just draw the head in white, and let it be.
     - Actually, the most common "simple" JS implementation just uses green.
     - For a bright head:
       `ctx.fillStyle = '#fff';`
       `ctx.fillText(char, x, y);`
       `ctx.fillStyle = '#0f0';`
       `ctx.fillText(char, x, y - fontSize);` // This doesn't work because we only draw the *new* char.

Let's rethink:
The trail is created by NOT clearing the screen fully.
If I draw a character in white at `y`, and in the next frame I draw a character in white at `y + fontSize`, the one at `y` is still white (but slightly faded).
If I want the one at `y` to be green, I have to change its color. But I can't change the color of something already drawn on the canvas.
UNLESS I redraw the trail every frame. But that's expensive.

Wait, I can do this:
1. Fill with `rgba(0, 0, 0, 0.05)`.
2. For each column:
   - `ctx.fillStyle = '#0F0';`
   - `ctx.fillText(char, x, y);`
   - `ctx.fillStyle = '#FFF';`
   - `ctx.fillText(char, x, y);`
   - Wait, if I draw it in white, it's white. Then it fades to black.
   - To make it fade to green, I'd need to draw green over it? No.

Actually, a common trick:
The "head" is just the character that was *just* drawn.
If I draw the current character in white, and then in the *next* frame, I draw the *new* character in white, the *previous* one is now the "tail".
To make the tail green, I can draw the current character in white, and then...
Wait! If I draw the character in white, and it fades... it doesn't turn green.

Let's use the "glow" or "layered" approach:
1. `ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; ctx.fillRect(0, 0, width, height);`
2. For each column:
   - Draw char at `y` in white.
   - This char is the head.
   - Next frame, this char is at `y`. New char is at `y+fontSize`.
   - The char at `y` is now part of the tail.
   - If I want it to be green, I could have drawn it in green... but then the head isn't white.

Actually, the most visually appealing way without complex buffers:
- Draw the character at `y` in white.
- Draw the character at `y - fontSize` in green.
- This means in every frame, for every column, we draw TWO characters?
  - One at `y` (the head) in white.
  - One at `y - fontSize` (the first part of the tail) in green.
- This way, the very front is white, and the rest is green.
- Since the `fillRect` fades everything, the green characters will also fade.

Let's try that:
- Column positions `y[i]`.
- In each frame:
  - `ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; ctx.fillRect(0, 0, w, h);`
  - For each column `i`:
    - `char = randomChar();`
    - `ctx.fillStyle = '#fff';`
    - `ctx.fillText(char, x, y[i]);`
    - `ctx.fillStyle = '#0f0';`
    - `ctx.fillText(char, x, y[i] - fontSize);`
    - `y[i] += fontSize;`
    - If `y[i] > h && Math.random() > 0.975` reset `y[i] = 0`.

Actually, if I do `ctx.fillText(char, x, y[i] - fontSize)` in green, and in the previous frame I did `ctx.fillText(char, x, y[i] - fontSize)` in white, the green will just overwrite the white.
So:
Frame N:
- Head at `y` is white.
- `y - fontSize` was white in Frame N-1. Now we draw it in green.
- `y - 2*fontSize` was white in Frame N-2, and green in Frame N-1. Now it's just fading.
This creates a white head and a green tail!

Let's refine the characters.
Katakana: `\u30A0` to `\u30FF`.
I'll use a string of common Matrix-like characters.

Implementation details:
- `window.innerWidth`, `window.innerHeight`.
- `canvas.width`, `canvas.height`.
- `ctx.font = '15px monospace'`.
- `fontSize = 15`.
- `columns = Math.floor(canvas.width / fontSize)`.
- `drops = new Array(columns).fill(1)`.

One more thing: the trailing fade. `rgba(0, 0, 0, 0.05)` might be too fast or too slow. `0.05` is usually good.

Let's write the code.
write index.html (3043 bytes)
toolResult

Successfully wrote 3043 bytes to index.html

assistant

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelgemma-4-31b-it
vendorGoogle
harnesspi-agent
generated2026-07-22

EVALUATION

4/5 working

Classic Matrix digital rain with falling green katakana, fading trails, and continuous animation; no interactivity but not required.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion42.0%
on click38.3%
on drag36.2%
on wheel35.3%
on enter + space34.0%
on arrow keys41.6%
on w/a/s/d35.0%
frame spread15.4 / 255
console errors0
js errors none

METRICS

runtime466.9s
tokens in1.4k
tokens out3.7k
cached0
cost / run$0.0015