Jekyll2026-03-20T03:47:54+00:00https://slide.ryoga.dev/feed.xmlslidePresentation slides powered by Reveal.jsRyoga.exeVeryl Css2026-03-20T00:00:00+00:002026-03-20T00:00:00+00:00https://slide.ryoga.dev/posts/veryl-cssVeryl の IR で遊んでみる
- 独自 target を生やしてみたかった話 -

</br>

Ryoga.exe

Kernel/VM探検隊@つくば No3


自己紹介

Ryoga.exe

- 筑波大学情報学群情報科学類 3 年 - やる:言語処理系とFPGAとCTF - X (Twitter)/mixi2: [@Ryoga_exe](https://x.com/Ryoga_exe)

最近作ったもの

  • FPGA 上に RISC-V CPU を作ったりした
  • その上で動く簡易的な OS も作った
  • その上でテトリスとかが動いた

筑波大学の COJT とかいう謎授業の自由課題で作った(CPU, OS 自作して単位が貰えて最高!)

CPU を作る中で Veryl という
モダンなハードウェア記述言語に出会った

Veryl とは

  • SystemVerilog ベースの新しい HDL
  • モダンで書きやすい構文
  • 既存の SystemVerilog 資産と連携しやすい
  • フォーマッタなどツール込みで使いやすい

Veryl の公式サイト

最近 IR が導入されたらしい

最近 IR が導入されたらしい

  • もともと Veryl は CST ベースの処理が多かった
  • しかし、エラーチェック(未代入やラッチ検出)には IR のほうが向いている

そこで IR が導入された

IR が入ると何が嬉しいのか?

  • 条件分岐が単純な形に落ちる
  • generics / parameter override を反映した状態で見られる
  • ビット単位の未代入検出/ラッチ検出がしやすい

将来的には IR を評価してシミュレータも
見えてくるらしい


思った

独自 target 生やせるのではないか

  • 公式 target は SystemVerilog
  • でも IR が公開されているなら、遊べそう

外から触れるのか

  • Veryl のリポジトリは Cargo workspace
  • crates/ 配下に analyzer などの crate がある
  • veryl-analyzerpub mod ir; を公開していて、AnalyzerContext も public に export している

[dependencies]
veryl-analyzer = "0.19.0"
veryl-metadata = "0.19.0"
veryl-parser = "0.19.0"

```rs [|8-9|11|13|15-17|19-23|33] use std::{env, fs};

use veryl_analyzer::{Analyzer, Context, ir::Ir}; use veryl_metadata::Metadata; use veryl_parser::Parser;

fn main() { let path = env::args().nth(1).unwrap(); let code = fs::read_to_string(&path).unwrap();

let metadata = Metadata::create_default("prj").unwrap();

let parser = Parser::parse(&code, &path).unwrap();

let analyzer = Analyzer::new(&metadata);
let mut context = Context::default();
let mut ir = Ir::default();

let mut errors = vec![];
errors.append(&mut analyzer.analyze_pass1("prj", &parser.veryl));
errors.append(&mut Analyzer::analyze_post_pass1());
errors.append(&mut analyzer.analyze_pass2("prj", &parser.veryl, &mut context, Some(&mut ir)));
errors.append(&mut Analyzer::analyze_post_pass2());

if !errors.is_empty() {
    eprintln!("analyzer errors:");
    for e in &errors {
        eprintln!("{e:?}");
    }
    eprintln!();
}

println!("{}", ir); } ``` <!-- .element: style="width: 100%; font-size: 0.5em;" -->

input (veryl): ```veryl module Counter ( clk: input clock, rst: input reset, o : output logic<8>, ) { always_ff { if_reset { o = 0; } else { o += 1; } } } ```
output (ir): ``` module Counter { input var0(clk): clock = 1'hx; input var1(rst): reset = 1'hx; output var2(o): logic<8> = 8'hxx; ff (var0, var1) { if_reset { var2 = 32'sh00000000; } else { var2 = (var2 + 32'sh00000001); } } } ```

眺めた感じ

どうにか何かはできそう


何を target にするか

SystemVerilog との共通点を考える

何を target にするか

SystemVerilog

  • 仕様書がデカい
  • 組合せ回路が記述できる
  • フリップフロップ回路が記述できる
  • CPU を作るのに使われる

  • 仕様書がデカい
  • 組合せ回路(っぽいもの)が記述できる
  • フリップフロップ回路(っぽいもの)が記述できる
  • CPU を作るのに使われる

Veryl to CSS を試みた話


</br>

Ryoga.exe

Kernel/VM探検隊@つくば No3


近年 CSS の進化は目覚ましい

CSS の表現力が劇的に向上

CSS で CPU が作られたことは記憶に新しい

しかし

  • CSS で複雑なロジックを組むのは大変
  • 実は CSS は複雑なロジックを組むのが目的の言語ではない

実は

Cascading Style Sheets

実は

Cascading Style Sheets

実は文書のスタイリングが主目的

なので

複雑なロジック部分をVerylで実装することにより
高度なCSSを実現する

input (veryl): ```veryl module Top ( a: input i32, b: input i32, c: output i32, ) { var t0: i32; always_comb { t0 = a + b; c = t0 + 5; } } ```
output (css): ```css :root { --t0: calc(var(--a) + var(--b)); --c: calc(var(--t0) - 5); } ```

つくったもの

https://github.com/Ryoga-exe/veryl-css

何ができるか

https://github.com/Ryoga-exe/veryl-css

  • always_comb / alawys_ff / if_reset / if / case / var
  • 一部の組込み型
  • 一部の演算子

を CSS にコンパイル可能


```veryl module seg7 ( d0 : input u8, d1 : input u8, d2 : input u8, d3 : input u8, out: output u8, s0 : output u8, s1 : output u8, s2 : output u8, s3 : output u8, s4 : output u8, s5 : output u8, s6 : output u8, ) { var data: u8; var seg: u8; always_comb { data = 8 * d0 + 4 * d1 + 2 * d2 + 1 * d3; out = data; case data { 0 : seg = 8'b0111111; 1 : seg = 8'b0000110; 2 : seg = 8'b1011011; 3 : seg = 8'b1001111; 4 : seg = 8'b1100110; 5 : seg = 8'b1101101; 6 : seg = 8'b1111101; 7 : seg = 8'b0000111; 8 : seg = 8'b1111111; 9 : seg = 8'b1101111; default: seg = 0; } s0 = seg[0]; s1 = seg[1]; s2 = seg[2]; s3 = seg[3]; s4 = seg[4]; s5 = seg[5]; s6 = seg[6]; } } ``` ```css /* generated by veryl-css */ @function --veryl-eq(--a , --b ) returns { result: clamp(0, calc(1 - abs(sign(calc(var(--a) - var(--b))))), 1); } @property --veryl-cond-0 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-1 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-2 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-3 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-4 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-5 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-6 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-7 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-8 { syntax: ""; inherits: true; initial-value: 0; } @property --veryl-cond-9 { syntax: ""; inherits: true; initial-value: 0; } @property --d0 { syntax: ""; inherits: true; initial-value: 0; } @property --d1 { syntax: ""; inherits: true; initial-value: 0; } @property --d2 { syntax: ""; inherits: true; initial-value: 0; } @property --d3 { syntax: ""; inherits: true; initial-value: 0; } @property --out { syntax: ""; inherits: true; initial-value: 0; } @property --s0 { syntax: ""; inherits: true; initial-value: 0; } @property --s1 { syntax: ""; inherits: true; initial-value: 0; } @property --s2 { syntax: ""; inherits: true; initial-value: 0; } @property --s3 { syntax: ""; inherits: true; initial-value: 0; } @property --s4 { syntax: ""; inherits: true; initial-value: 0; } @property --s5 { syntax: ""; inherits: true; initial-value: 0; } @property --s6 { syntax: ""; inherits: true; initial-value: 0; } @property --seg7-data { syntax: ""; inherits: true; initial-value: 0; } @property --seg7-seg { syntax: ""; inherits: true; initial-value: 0; } :root { --seg7-data: calc((calc((calc((calc((8) * (var(--d0)))) + (calc((4) * (var(--d1)))))) + (calc((2) * (var(--d2)))))) + (calc((1) * (var(--d3))))); --out: var(--seg7-data); --veryl-cond-0: --veryl-eq(var(--seg7-data), 0); --veryl-cond-1: --veryl-eq(var(--seg7-data), 1); --veryl-cond-2: --veryl-eq(var(--seg7-data), 2); --veryl-cond-3: --veryl-eq(var(--seg7-data), 3); --veryl-cond-4: --veryl-eq(var(--seg7-data), 4); --veryl-cond-5: --veryl-eq(var(--seg7-data), 5); --veryl-cond-6: --veryl-eq(var(--seg7-data), 6); --veryl-cond-7: --veryl-eq(var(--seg7-data), 7); --veryl-cond-8: --veryl-eq(var(--seg7-data), 8); --veryl-cond-9: --veryl-eq(var(--seg7-data), 9); --seg7-seg: if(style(--veryl-cond-0: 1): 63; else: if(style(--veryl-cond-1: 1): 6; else: if(style(--veryl-cond-2: 1): 91; else: if(style(--veryl-cond-3: 1): 79; else: if(style(--veryl-cond-4: 1): 102; else: if(style(--veryl-cond-5: 1): 109; else: if(style(--veryl-cond-6: 1): 125; else: if(style(--veryl-cond-7: 1): 7; else: if(style(--veryl-cond-8: 1): 127; else: if(style(--veryl-cond-9: 1): 111; else: 0)))))))))); --s0: mod(var(--seg7-seg), 2); --s1: mod(round(down, var(--seg7-seg) / 2), 2); --s2: mod(round(down, var(--seg7-seg) / 4), 2); --s3: mod(round(down, var(--seg7-seg) / 8), 2); --s4: mod(round(down, var(--seg7-seg) / 16), 2); --s5: mod(round(down, var(--seg7-seg) / 32), 2); --s6: mod(round(down, var(--seg7-seg) / 64), 2); } ``` </div> --

CSS だけでモンテカルロ法を実装する

→ 本当に CSS はなんでもできる?


「ビューポート幅 (px) の 数値 が欲しい!」

:root {
  --px-width: calc(100vw / 1px);
}

結果 → 無効

CSS の限界

現行のブラウザでの実装では
calc() はまだ単位付き同士の除算ができない

div {
  width: calc(100vw / 5px);
}

本当に?

↑ 余談:w3.org は埋め込みを許してくれない

https://www.w3.org/TR/css-values-4/#calc-type-checking

まあなんか、仕様的にはOK

しかし実装を待ってられない!!

実際にあなたがブラウザの実装を待っている間にも
ライバルはCSSで黒魔術を続けている

今日はこれを回避するテク


元ネタ

CSS Type Casting to Numeric: tan(atan2()) Scalars - Jane Ori

https://dev.to/janeori/css-type-casting-to-numeric-tanatan2-scalars-582j


そういえば最近のCSSのアップデートは目覚ましい

そういえば最近のCSSのアップデートは目覚ましい

ここでおもむろに CSS WG の CSS Values and Units Module Level 4 を見てみる

  • なぜかネイピア数 ($e$) や円周率 $\pi$ などの定数が追加されている
  • minmaxclamp といった比較関数が追加されている

その他にも

  • 端数処理: round
  • 剰余関数: rem, mod
  • 冪乗: pow
  • 平方根: sqrt
  • 対数: log
  • 指数: exp
  • 絶対値: abs
  • 符号関数: sign
  • 三角関数・逆三角関数: sin, cos, tan, asin, …

余談:これらを組み合わせると……

  • 黄金数: calc((1 + sqrt(5)) / 2)
  • ゲルフォントの定数: calc(pow(e, pi))

などが CSS で使うことができる

いつ使うん?


ところでこのような三角恒等式がある

\[\begin{aligned} \tan( \mathrm{atan2}(Y, X) ) = \frac{Y}{X} \end{aligned} \]

  • atan2(y, x) は傾き y/x の角度 $\theta$ を表す
  • その角度に tan() を適用 → もとの比率 y/x が戻る

CSS には tan()atan2 がある

tan(atan2()) は単なるスカラー値になる

ブラウザは単位付き値でも評価してくれる

つまり、

:root {
  --px-width: tan(atan2(100vw, 1px))
}

とすると、100vw が何ピクセルであるか得られる

長さをキャストして <number> 型として得る


Viewport を取る例

https://codepen.io/Ryoga-exe/full/KwwYKym

その他にも

その他にも

  • フォントサイズ (rempx)
    • tan(atan2(1em, 1px))
    • https://codepen.io/propjockey/full/WNLLLWy

その他にも

  • Container幅 (CQ)
    • tan(atan2(100cqi, 1px))

その他にも

  • 時間 (sms)
    • tan(atan2(12s, 1ms))

おわりに

みなさんも黒魔術 CSS を書こう!

]]>Ryoga.exeTrick Of Css2023-12-03T00:00:00+00:002023-12-03T00:00:00+00:00https://slide.ryoga.dev/posts/trick-of-cssCSS 黒魔術
- CSS だけでモンテカルロ法を実装する -

</br>

Ryoga.exe


自己紹介

Ryoga.exe

- 筑波大学情報学群情報科学類 1 年 - 競プロ・CTF・Web をしています - 低レイヤも好き - Twitter: @Ryoga_exe

最近作ったもの

これは何

  • 見てわかる通りモンテカルロ法を使った円周率の推定
  • CSS だけで実装しています

本当に CSS だけ?

本当に CSS だけ?

はい


CSS の厳しいところ

  • 乱数を得るための関数がない
  • 基本的に四則演算しかできない
  • それどころか、変数の状態を再評価する機能がない
  • そもそも変数の値をまともに表示できない

もしかして:不可能?

なんと The CPU Hack と呼ばれる CSS トリックと数学を頑張れば可能! The CPU Hack - https://dev.to/janeori/expert-css-the-cpu-hack-4ddj

The CPU Hack とは

詳しい仕組みは The CPU Hack の元記事を参照

簡単に説明すると、継続的なデータの解析と、状態を再評価する機能を解除する CSS のトリック

アニメーションの仕様を用いてフレーム数のカウントなどができます

いわゆる黒魔術

フレーム数をカウントする CSS

The CPU Hack の本質部分のコード

```css [1-7|5-6|2-3|8-16|10|15|18-24|26-37] body { animation: hoist 1ms infinite, capture 1ms infinite; animation-play-state: paused, paused;

–frame-input: var(–frame-hoist, 0); –frame-count: calc(var(–frame-input) + 1); } @keyframes hoist { 0%, 100% { –frame-hoist: var(–frame-captured, 0); } } @keyframes capture { 0%, 100% { –frame-captured: var(–frame-count); } } .cpu { position: relative; list-style: none; } .cpu > * { position: absolute; inset: 0px; width: 0px; } .cpu > .phase-0 { width: 100%; } .cpu > .phase-0:hover + .phase-1 { width: 100%; } .cpu > .phase-1:hover + .phase-2 { width: 100%; } .cpu > .phase-2:hover + .phase-3 { width: 100%; }


---

## CSS だけで疑似乱数列を生成

CSS には乱数を得るための関数はない

--

csswg-drafts の Issue に提案として上がってはいる

![csswg-drafts](/assets/img/csswg.png)

--

mozilla の standards-positions にも上がっているが

<div class="r-stack">
  <img src="proxy.php?url=/assets/img/mozilla.png" />
  <img class="fragment" src="proxy.php?url=/assets/img/mozilla2.png"/>
</div>

<span class="fragment">mozilla の見解:いらんやろ</span>

--

## 無いのならば作る

今回は比較的実装が容易かつシンプルな疑似乱数列生成法である <span class="fragment highlight-red">Xorshift</span> を採用

--

## Wikipedia の実装例を読む

```cpp
/* The state word must be initialized to non-zero */
uint32_t xorshift32(struct xorshift32_state *state)
{
	/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
	uint32_t x = state->a;
	x ^= x << 13;
	x ^= x >> 17;
	x ^= x << 5;
	return state->a = x;
}

CSS にはビット演算がない、詰み

数学をする

$A, B$ を 1 bit の変数とすると、以下が成り立つ

$A$ $B$ $A \mathbin{xor} B$ $(A - B)$ $(A - B)^2$
0 0 0 0 0
0 1 1 -1 1
1 0 1 1 1
1 1 0 0 0

\[A \mathbin{xor} B = (A - B) \times (A - B)\]

が言えるので 1bit ならば四則演算で表現可能!

ビットシフトはビットごと個別に変数を持ち、
一つづつずらしていくように更新すればよさそう

つまり今回は 32bit の変数が必要なので…

32 個の変数を持つ (狂気の CSS)

Xorshift の実装の一部

(乱数の初期値は 2463534242)

body {
  animation: hoist 1ms infinite, capture 1ms infinite;
  animation-play-state: paused, paused;

  --p31-input: var(--p31-hoist, 1);
  --p30-input: var(--p30-hoist, 0);
  --p29-input: var(--p29-hoist, 0);
  --p28-input: var(--p28-hoist, 1);
  --p27-input: var(--p27-hoist, 0);
  --p26-input: var(--p26-hoist, 0);
  --p25-input: var(--p25-hoist, 1);
  --p24-input: var(--p24-hoist, 0);
  --p23-input: var(--p23-hoist, 1);
  --p22-input: var(--p22-hoist, 1);
  --p21-input: var(--p21-hoist, 0);
  --p20-input: var(--p20-hoist, 1);
  --p19-input: var(--p19-hoist, 0);
  --p18-input: var(--p18-hoist, 1);
  --p17-input: var(--p17-hoist, 1);
  --p16-input: var(--p16-hoist, 0);
  --p15-input: var(--p15-hoist, 1);
  --p14-input: var(--p14-hoist, 0);
  --p13-input: var(--p13-hoist, 0);
  --p12-input: var(--p12-hoist, 0);
  --p11-input: var(--p11-hoist, 1);
  --p10-input: var(--p10-hoist, 1);
  --p09-input: var(--p09-hoist, 0);
  --p08-input: var(--p08-hoist, 0);
  --p07-input: var(--p07-hoist, 1);
  --p06-input: var(--p06-hoist, 0);
  --p05-input: var(--p05-hoist, 1);
  --p04-input: var(--p04-hoist, 0);
  --p03-input: var(--p03-hoist, 0);
  --p02-input: var(--p02-hoist, 0);
  --p01-input: var(--p01-hoist, 1);
  --p00-input: var(--p00-hoist, 0);

  /*
    q = (p_in xor (p_in << 13))
    r = (q xor (q >> 17))
    p = (r xor (r << 5))
  */
  --q31: calc((var(--p31-input) - var(--p18-input)) * (var(--p31-input) - var(--p18-input)));
  --q30: calc((var(--p30-input) - var(--p17-input)) * (var(--p30-input) - var(--p17-input)));
  --q29: calc((var(--p29-input) - var(--p16-input)) * (var(--p29-input) - var(--p16-input)));
  --q28: calc((var(--p28-input) - var(--p15-input)) * (var(--p28-input) - var(--p15-input)));
  --q27: calc((var(--p27-input) - var(--p14-input)) * (var(--p27-input) - var(--p14-input)));
  --q26: calc((var(--p26-input) - var(--p13-input)) * (var(--p26-input) - var(--p13-input)));
  --q25: calc((var(--p25-input) - var(--p12-input)) * (var(--p25-input) - var(--p12-input)));
  --q24: calc((var(--p24-input) - var(--p11-input)) * (var(--p24-input) - var(--p11-input)));
  --q23: calc((var(--p23-input) - var(--p10-input)) * (var(--p23-input) - var(--p10-input)));
  --q22: calc((var(--p22-input) - var(--p09-input)) * (var(--p22-input) - var(--p09-input)));
  --q21: calc((var(--p21-input) - var(--p08-input)) * (var(--p21-input) - var(--p08-input)));
  --q20: calc((var(--p20-input) - var(--p07-input)) * (var(--p20-input) - var(--p07-input)));
  --q19: calc((var(--p19-input) - var(--p06-input)) * (var(--p19-input) - var(--p06-input)));
  --q18: calc((var(--p18-input) - var(--p05-input)) * (var(--p18-input) - var(--p05-input)));
  --q17: calc((var(--p17-input) - var(--p04-input)) * (var(--p17-input) - var(--p04-input)));
  --q16: calc((var(--p16-input) - var(--p03-input)) * (var(--p16-input) - var(--p03-input)));
  --q15: calc((var(--p15-input) - var(--p02-input)) * (var(--p15-input) - var(--p02-input)));
  --q14: calc((var(--p14-input) - var(--p01-input)) * (var(--p14-input) - var(--p01-input)));
  --q13: calc((var(--p13-input) - var(--p00-input)) * (var(--p13-input) - var(--p00-input)));
  --q12: calc((var(--p12-input) - 0) * (var(--p12-input) - 0));
  --q11: calc((var(--p11-input) - 0) * (var(--p11-input) - 0));
  --q10: calc((var(--p10-input) - 0) * (var(--p10-input) - 0));
  --q09: calc((var(--p09-input) - 0) * (var(--p09-input) - 0));
  --q08: calc((var(--p08-input) - 0) * (var(--p08-input) - 0));
  --q07: calc((var(--p07-input) - 0) * (var(--p07-input) - 0));
  --q06: calc((var(--p06-input) - 0) * (var(--p06-input) - 0));
  --q05: calc((var(--p05-input) - 0) * (var(--p05-input) - 0));
  --q04: calc((var(--p04-input) - 0) * (var(--p04-input) - 0));
  --q03: calc((var(--p03-input) - 0) * (var(--p03-input) - 0));
  --q02: calc((var(--p02-input) - 0) * (var(--p02-input) - 0));
  --q01: calc((var(--p01-input) - 0) * (var(--p01-input) - 0));
  --q00: calc((var(--p00-input) - 0) * (var(--p00-input) - 0));

  --r31: calc((var(--q31) - 0) * (var(--q31) - 0));
  --r30: calc((var(--q30) - 0) * (var(--q30) - 0));
  --r29: calc((var(--q29) - 0) * (var(--q29) - 0));
  --r28: calc((var(--q28) - 0) * (var(--q28) - 0));
  --r27: calc((var(--q27) - 0) * (var(--q27) - 0));
  --r26: calc((var(--q26) - 0) * (var(--q26) - 0));
  --r25: calc((var(--q25) - 0) * (var(--q25) - 0));
  --r24: calc((var(--q24) - 0) * (var(--q24) - 0));
  --r23: calc((var(--q23) - 0) * (var(--q23) - 0));
  --r22: calc((var(--q22) - 0) * (var(--q22) - 0));
  --r21: calc((var(--q21) - 0) * (var(--q21) - 0));
  --r20: calc((var(--q20) - 0) * (var(--q20) - 0));
  --r19: calc((var(--q19) - 0) * (var(--q19) - 0));
  --r18: calc((var(--q18) - 0) * (var(--q18) - 0));
  --r17: calc((var(--q17) - 0) * (var(--q17) - 0));
  --r16: calc((var(--q16) - 0) * (var(--q16) - 0));
  --r15: calc((var(--q15) - 0) * (var(--q15) - 0));
  --r14: calc((var(--q14) - var(--q31)) * (var(--q14) - var(--q31)));
  --r13: calc((var(--q13) - var(--q30)) * (var(--q13) - var(--q30)));
  --r12: calc((var(--q12) - var(--q29)) * (var(--q12) - var(--q29)));
  --r11: calc((var(--q11) - var(--q28)) * (var(--q11) - var(--q28)));
  --r10: calc((var(--q10) - var(--q27)) * (var(--q10) - var(--q27)));
  --r09: calc((var(--q09) - var(--q26)) * (var(--q09) - var(--q26)));
  --r08: calc((var(--q08) - var(--q25)) * (var(--q08) - var(--q25)));
  --r07: calc((var(--q07) - var(--q24)) * (var(--q07) - var(--q24)));
  --r06: calc((var(--q06) - var(--q23)) * (var(--q06) - var(--q23)));
  --r05: calc((var(--q05) - var(--q22)) * (var(--q05) - var(--q22)));
  --r04: calc((var(--q04) - var(--q21)) * (var(--q04) - var(--q21)));
  --r03: calc((var(--q03) - var(--q20)) * (var(--q03) - var(--q20)));
  --r02: calc((var(--q02) - var(--q19)) * (var(--q02) - var(--q19)));
  --r01: calc((var(--q01) - var(--q18)) * (var(--q01) - var(--q18)));
  --r00: calc((var(--q00) - var(--q17)) * (var(--q00) - var(--q17)));

  --p31: calc((var(--r31) - var(--r26)) * (var(--r31) - var(--r26)));
  --p30: calc((var(--r30) - var(--r25)) * (var(--r30) - var(--r25)));
  --p29: calc((var(--r29) - var(--r24)) * (var(--r29) - var(--r24)));
  --p28: calc((var(--r28) - var(--r23)) * (var(--r28) - var(--r23)));
  --p27: calc((var(--r27) - var(--r22)) * (var(--r27) - var(--r22)));
  --p26: calc((var(--r26) - var(--r21)) * (var(--r26) - var(--r21)));
  --p25: calc((var(--r25) - var(--r20)) * (var(--r25) - var(--r20)));
  --p24: calc((var(--r24) - var(--r19)) * (var(--r24) - var(--r19)));
  --p23: calc((var(--r23) - var(--r18)) * (var(--r23) - var(--r18)));
  --p22: calc((var(--r22) - var(--r17)) * (var(--r22) - var(--r17)));
  --p21: calc((var(--r21) - var(--r16)) * (var(--r21) - var(--r16)));
  --p20: calc((var(--r20) - var(--r15)) * (var(--r20) - var(--r15)));
  --p19: calc((var(--r19) - var(--r14)) * (var(--r19) - var(--r14)));
  --p18: calc((var(--r18) - var(--r13)) * (var(--r18) - var(--r13)));
  --p17: calc((var(--r17) - var(--r12)) * (var(--r17) - var(--r12)));
  --p16: calc((var(--r16) - var(--r11)) * (var(--r16) - var(--r11)));
  --p15: calc((var(--r15) - var(--r10)) * (var(--r15) - var(--r10)));
  --p14: calc((var(--r14) - var(--r09)) * (var(--r14) - var(--r09)));
  --p13: calc((var(--r13) - var(--r08)) * (var(--r13) - var(--r08)));
  --p12: calc((var(--r12) - var(--r07)) * (var(--r12) - var(--r07)));
  --p11: calc((var(--r11) - var(--r06)) * (var(--r11) - var(--r06)));
  --p10: calc((var(--r10) - var(--r05)) * (var(--r10) - var(--r05)));
  --p09: calc((var(--r09) - var(--r04)) * (var(--r09) - var(--r04)));
  --p08: calc((var(--r08) - var(--r03)) * (var(--r08) - var(--r03)));
  --p07: calc((var(--r07) - var(--r02)) * (var(--r07) - var(--r02)));
  --p06: calc((var(--r06) - var(--r01)) * (var(--r06) - var(--r01)));
  --p05: calc((var(--r05) - var(--r00)) * (var(--r05) - var(--r00)));
  --p04: calc((var(--r04) - 0) * (var(--r04) - 0));
  --p03: calc((var(--r03) - 0) * (var(--r03) - 0));
  --p02: calc((var(--r02) - 0) * (var(--r02) - 0));
  --p01: calc((var(--r01) - 0) * (var(--r01) - 0));
  --p00: calc((var(--r00) - 0) * (var(--r00) - 0));
}

なんとか乱数列ぽいのができた

次に、このビット列から数値を得る

上位 16 ビットを x 座標に
下位ビットを y 座標に割り当てた

10 進数にしたのち、範囲を $[0, 1]$ に収めるため、
最大値の $65535$ で割っている

body {
  --x: calc(
    (
      var(--p31) * 32768 +
      var(--p30) * 16384 +
      var(--p29) * 8192 +
      var(--p28) * 4096 +
      var(--p27) * 2048 +
      var(--p26) * 1024 +
      var(--p25) * 512 +
      var(--p24) * 256 +
      var(--p23) * 128 +
      var(--p22) * 64 +
      var(--p21) * 32 +
      var(--p20) * 16 +
      var(--p19) * 8 +
      var(--p18) * 4 +
      var(--p17) * 2 +
      var(--p16) * 1
    ) / 65535
  );
  --y: calc(
    (
      var(--p15) * 32768 +
      var(--p14) * 16384 +
      var(--p13) * 8192 +
      var(--p12) * 4096 +
      var(--p11) * 2048 +
      var(--p10) * 1024 +
      var(--p09) * 512 +
      var(--p08) * 256 +
      var(--p07) * 128 +
      var(--p06) * 64 +
      var(--p05) * 32 +
      var(--p04) * 16 +
      var(--p03) * 8 +
      var(--p02) * 4 +
      var(--p01) * 2 +
      var(--p00) * 1
    ) / 65535
  );
}

点が円の内部にあるかの判定

しかし、もちろん CSS には if 文などない

ここでもまた数学を頑張る

「点 $(x, y)$ が円内にあるとき変数 $c$ をインクリメントする」は

「変数 $c$ に $f(x, y)$ を足す (ただし、関数 $f(x, y)$ は点 $(x, y)$ が円内にあるときは $1$ を、そうでないときは $0$ を返すような関数)」と書けそう

ではそんな $f(x, y)$ を考えてみる

円の半径が $r$ でその中心が $(0, 0)$ のとき、点 $(x, y)$ がこの円の中に入っているかどうかは $x^2 + y^2 \leq r^2$ で表せる

つまり $f(x, y) = g(x^2 + y^2)$ (ただし $g(t)$ は $t$ が $r^2$ 以下であるとき $1$ を、そうでないときは $0$ を返すような関数) と表現できる

CSS で表現できるのは四則演算や最も近い整数に丸める処理 (Round)、そして max, min, clamp といった処理です。この中で関数 $g(t)$ を表現してみる

試行錯誤すると以下のようなものが見つかった

\[\operatorname{floor}\left(\max\left(\min\left(-t\ +\ 2,\ 1\right),\ 0\right)\right)\]

g(t) のグラフ

やった!実装ができます

→ うれしい、CSS はパズルです


変数を表示する

CSS 変数を表示するには CSS カウンターを使用する

例えば変数 --hoge を表示したいとき、

<div class="display-hoge"></div>

のような div 要素を作り

.display-hoge::after {
  counter-reset: hoge var(--hoge);
  content: "--hoge: " counter(hoge);
}

MDN を読む

しかし、MDN Web Docs で counter-reset について調べてみると、カウンターの初期値には <integer> 型、つまり整数型しか指定できない

仕様書を読む

W3C の CSS Values and Units Module Level 4
でこれらの型について定義されている。

これの [5.2.1. Computation and Combination of ](https://drafts.csswg.org/css-values/#combine-integers)
を読むと…

実数型であるところの <number><integer> に変換すると、結果は最も近い整数に丸められることがわかる。

例えば、先程のコードで --hoge が 2.5 であるとき、3 と表示されてしまう

困った

数学を頑張ってゴリ押す

例えば $x = 1.23$ という $x$ があったとする

整数部分は $\operatorname{floor}(x)$ と表すことができ、
また小数部分は $x - \operatorname{floor}(x)$ と表せる

これを $y$ とおくと、$y = 0.23$ なので、$10y = 2.3$

$x$ を $10y$ で置き換えて同様のことをすると
$\operatorname{floor}(x) = 2$ となり、少数第一位の桁を取り出すことができる!

$\operatorname{floor}(x) = \operatorname{round}(x - 0.5)$ なのでこの方法は CSS で表現が可能!

これを繰り返すことによって少数点以下の各桁を得ることができる!

もちろん変数による CSS には繰り返し処理など無いので ゴミカスごちゃごちゃ CSS を書く

小数点以下まで表示する例

例えば先程のコードで --hoge が 1.234 のとき、
小数点以下 3 桁を表示するには以下のようにする

```css [|2|5|8|10|12-15|17-21|22-28] .display-hoge::after { –hoge: 1.234;

/* hoge の整数部分 (=1) */ –floor-hoge: calc(var(–hoge) - 0.5);

/* hoge の少数部分 * 10 (=2.34) / –hoge-decimal00-in: calc((var(–hoge) - var(–floor-hoge)) * 10); / (hoge の少数部分 * 10) の整数部分 (=2) / –hoge-decimal00: calc(var(–hoge-decimal00-in) - 0.5); / 以下同様に繰り返す */ –hoge-decimal01-in: calc((var(–hoge-decimal00-in) - var(–hoge-decimal00)) * 10); –hoge-decimal01: calc(var(–hoge-decimal01-in) - 0.5); –hoge-decimal02-in: calc((var(–hoge-decimal01-in) - var(–hoge-decimal01)) * 10); –hoge-decimal02: calc(var(–hoge-decimal02-in) - 0.5);

counter-reset: floor-hoge var(–floor-hoge) hoge-decimal00 var(hoge-decimal00) hoge-decimal01 var(hoge-decimal01) hoge-decimal02 var(hoge-decimal02); content: “–hoge: “ counter(floor-hoge) “.” counter(floor-decimal00) counter(floor-decimal01) counter(floor-decimal02); } ```


終わりに

みなさんも黒魔術 CSS を書こう!

End

made with reveal.js and Jekyll

]]>
Ryoga.exe
Example2021-04-08T00:00:00+00:002021-04-08T00:00:00+00:00https://slide.ryoga.dev/posts/exampleExample slide
- example subtitle -

</br>

Ryoga.exe


HELLO THERE!


VERTICAL SLIDES

BASEMENT LEVEL 1

BASEMENT LEVEL 2


FRAGMENTS

  • List1
  • List2
  • List3

  • Fade in
  • Fade out
  • Highlight red
  • Fade in, then out
  • Slide up while fading in

CODE HIGHLIGHT

#include <iostream>
using namespace std;

int main() {
  int a = 0;
  cout << "Hello world!" << endl;
  return 0;
}

CODE

```cpp [1|4-21|6|9|12|15] #include using namespace std;

int main() { for (int i = 0; i <= 100; i++) { if (i % 3 == 0) { cout « “Fizz “; } else if (i % 5 == 0) { cout « “Buzz “; } else if (i % 15 == 0) { cout « “FizzBuzz “; } else { cout « i « ” “; } } cout « endl; return 0; } ```


AUTO-ANIMATE



  let planets = [
    { name: 'mars', diameter: 6779 },
  ]


  let planets = [
    { name: 'mars', diameter: 6779 },
    { name: 'earth', diameter: 12742 },
    { name: 'jupiter', diameter: 139820 }
  ]


  let circumferenceReducer = ( c, planet ) => {
    return c + planet.diameter * Math.PI;
  }

  let planets = [
    { name: 'mars', diameter: 6779 },
    { name: 'earth', diameter: 12742 },
    { name: 'jupiter', diameter: 139820 }
  ]

  let c = planets.reduce( circumferenceReducer, 0 )


IMPLICIT

IMPLICIT

ANIMATION


  • C++
  • Java
  • Python

  • C++
  • JavaScript
  • Java
  • Go
  • Python

FIT TEXT

CAN BE USED FOR MULTIPLE HEADLINES


STACK


#aaa

Background

https://pbs.twimg.com/media/FMfke2NVQAEUhAS?format=jpg&name=4096x4096

background-image


zoom-in fade-out

Transition


Note

Note: aaaaaaaaaa


TABLE

header1 header2 header3
align left align right align center
a b c

Item Value
CPU Intel™ core-i7 9700K
RAM DDR4 32GB
GPU GeForce RTX2060

Image

Image


The Lorenz Equations

\[\begin{aligned} \dot{x} &amp; = \sigma(y-x) \\ \dot{y} &amp; = \rho x - y - xz \\ \dot{z} &amp; = -\beta z + xy \end{aligned} \]


LEFT


End

made with reveal.js and Jekyll

]]>
Ryoga.exe