docs: add readme and license, translate to english
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Ku6epXBOCTuK
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# CSS Matrix3D Perspective Calculator
|
||||||
|
|
||||||
|
A browser-based tool for generating CSS `matrix3d()` transforms with perspective projection. Define 4 corners on a field and a widget size — get ready-to-use CSS code.
|
||||||
|
|
||||||
|
**Keywords:** CSS matrix3d, perspective transform, 3D CSS, homography, quadrilateral mapping, CSS transform generator, perspective projection, CSS 3D effects
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Open `index.html` in a browser (no build step required).
|
||||||
|
|
||||||
|
- **Edit** — drag corners on the SVG field, adjust field and widget sizes
|
||||||
|
- **Preview** — see the live matrix3d() transform result
|
||||||
|
|
||||||
|
Copy the CSS from the "CSS Output" section and paste into your project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Pure math — homography-based matrix3d() calculation
|
||||||
|
- Live preview with real-time updates
|
||||||
|
- Drag-and-drop corner positioning
|
||||||
|
- Editable field dimensions with aspect ratio lock
|
||||||
|
- Rescale coordinates option when resizing the field
|
||||||
|
- Zero dependencies, runs in any modern browser
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
- **Presentations & landing pages** — render a widget or screenshot on a monitor at any angle
|
||||||
|
- **Carousels & galleries** — show product cards with perspective deformation
|
||||||
|
- **Interactive infographics** — overlay data on maps or charts with perspective
|
||||||
|
- **App previews** — place mobile UI on a device background
|
||||||
|
- **Scroll-based effects** — animate matrix3d for 3D effects without WebGL
|
||||||
|
- **Mockups & prototypes** — visually place interfaces in context (on a wall, laptop, banner)
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```text
|
||||||
|
├── index.html
|
||||||
|
├── style.css
|
||||||
|
└── js/
|
||||||
|
├── main.js — entry point
|
||||||
|
├── state.js — state management
|
||||||
|
├── homography.js — homography math
|
||||||
|
├── svg-renderer.js — SVG rendering
|
||||||
|
├── drag.js — drag handling
|
||||||
|
├── inputs.js — input fields
|
||||||
|
├── preview.js — live preview
|
||||||
|
└── ui.js — buttons and modes
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The tool uses [homography](https://en.wikipedia.org/wiki/Homography_(computer_vision)) to compute a 3D perspective transform from 4 corresponding points. The resulting `matrix3d()` CSS property maps a rectangular widget onto an arbitrary quadrilateral defined by the user.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
+12
-12
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="ru">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
<header>
|
<header>
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<h1>CSS Matrix3D Perspective Calculator</h1>
|
<h1>CSS Matrix3D Perspective Calculator</h1>
|
||||||
<p>Задайте 4 точки на поле и размер виджета — получите CSS matrix3d() для перспективного отображения</p>
|
<p>Set 4 corners on the field and widget size — get CSS matrix3d() for perspective rendering</p>
|
||||||
</div>
|
</div>
|
||||||
<span class="mode-hint" id="modeHint">Перетаскивайте углы на поле</span>
|
<span class="mode-hint" id="modeHint">Drag corners on the field</span>
|
||||||
<div class="mode-toggle">
|
<div class="mode-toggle">
|
||||||
<button class="mode-btn active" id="btnEdit">Edit</button>
|
<button class="mode-btn active" id="btnEdit">Edit</button>
|
||||||
<button class="mode-btn" id="btnPreview">Preview</button>
|
<button class="mode-btn" id="btnPreview">Preview</button>
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
<div class="right-col">
|
<div class="right-col">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Основное поле</h2>
|
<h2>Field</h2>
|
||||||
<button class="btn btn-edit-field" id="btnEditField">Редактировать</button>
|
<button class="btn btn-edit-field" id="btnEditField">Edit</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-size-stack">
|
<div class="field-size-stack">
|
||||||
<div class="chain-link" id="chainLink" title="Keep aspect ratio">
|
<div class="chain-link" id="chainLink" title="Keep aspect ratio">
|
||||||
@@ -68,17 +68,17 @@
|
|||||||
<div class="field-edit-options" id="fieldEditOptions">
|
<div class="field-edit-options" id="fieldEditOptions">
|
||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
<input type="checkbox" id="chkRescaleCoords" checked />
|
<input type="checkbox" id="chkRescaleCoords" checked />
|
||||||
<span>Пересчитать координаты</span>
|
<span>Rescale coordinates</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="field-save-row">
|
<div class="field-save-row">
|
||||||
<button class="btn btn-cancel-field" id="btnCancelField">Отменить</button>
|
<button class="btn btn-cancel-field" id="btnCancelField">Cancel</button>
|
||||||
<button class="btn btn-save-field" id="btnSaveField">Сохранить</button>
|
<button class="btn btn-save-field" id="btnSaveField">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<h2>Виджет</h2>
|
<h2>Widget</h2>
|
||||||
<div class="field-row">
|
<div class="field-row">
|
||||||
<label><span>W</span><input id="inpWidgetW" type="number" value="400" min="1" /></label>
|
<label><span>W</span><input id="inpWidgetW" type="number" value="400" min="1" /></label>
|
||||||
<label><span>H</span><input id="inpWidgetH" type="number" value="300" min="1" /></label>
|
<label><span>H</span><input id="inpWidgetH" type="number" value="300" min="1" /></label>
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<h2>Углы четырёхугольника</h2>
|
<h2>Corners</h2>
|
||||||
<div class="corner-inputs" id="cornerInputs"></div>
|
<div class="corner-inputs" id="cornerInputs"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -94,8 +94,8 @@
|
|||||||
<h2>CSS Output</h2>
|
<h2>CSS Output</h2>
|
||||||
<textarea id="cssOutput" rows="10" readonly></textarea>
|
<textarea id="cssOutput" rows="10" readonly></textarea>
|
||||||
<div class="btn-row">
|
<div class="btn-row">
|
||||||
<button class="btn btn-copy" id="copyBtn">Копировать CSS</button>
|
<button class="btn btn-copy" id="copyBtn">Copy CSS</button>
|
||||||
<button class="btn btn-reset" id="resetBtn">Сброс</button>
|
<button class="btn btn-reset" id="resetBtn">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ export function computeHomography(state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toMatrix3dCSS(H) {
|
export function toMatrix3dCSS(H) {
|
||||||
if (!H) return '/* вырожденная конфигурация */';
|
if (!H) return '/* degenerate configuration */';
|
||||||
const n = v => parseFloat(v.toFixed(8));
|
const n = v => parseFloat(v.toFixed(8));
|
||||||
return [
|
return [
|
||||||
'transform-origin: 0 0;',
|
'transform-origin: 0 0;',
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ function setMode(mode) {
|
|||||||
$('btnEdit').classList.toggle('active', mode === 'edit');
|
$('btnEdit').classList.toggle('active', mode === 'edit');
|
||||||
$('btnPreview').classList.toggle('active', mode === 'preview');
|
$('btnPreview').classList.toggle('active', mode === 'preview');
|
||||||
$('modeHint').textContent = mode === 'edit'
|
$('modeHint').textContent = mode === 'edit'
|
||||||
? 'Перетаскивайте углы на поле'
|
? 'Drag corners on the field'
|
||||||
: 'Результат matrix3d() трансформации';
|
: 'matrix3d() transform result';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateCSSOutput(state) {
|
export function updateCSSOutput(state) {
|
||||||
@@ -139,7 +139,7 @@ export function initUI(state, updateAll) {
|
|||||||
navigator.clipboard.writeText(text).then(() => {
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
const btn = $('copyBtn');
|
const btn = $('copyBtn');
|
||||||
const orig = btn.textContent;
|
const orig = btn.textContent;
|
||||||
btn.textContent = 'Скопировано!';
|
btn.textContent = 'Copied!';
|
||||||
setTimeout(() => btn.textContent = orig, 1500);
|
setTimeout(() => btn.textContent = orig, 1500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user