Repository: mantoufan/yzhanWeather
Branch: master
Commit: 9bf902801dad
Files: 10
Total size: 22.2 KB
Directory structure:
gitextract_im5qcwqy/
├── .gitignore
├── .swcrc
├── LICENSE
├── README.md
├── docs/
│ └── index.html
├── old/
│ └── mtfWeather.js
├── package.json
├── src/
│ ├── conf.js
│ └── yzhanweather.js
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
================================================
FILE: .swcrc
================================================
{
"$schema": "https://json.schemastore.org/swcrc",
"minify": false
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 馒头饭
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.
================================================
FILE: README.md
================================================
# yzhanWeather



[](https://github.com/mantoufan/yzhanweather/blob/main/LICENSE)

Pure CSS animation for sakura, rain, snow, firefly and butterfly effects, high performance without affecting SEO
纯 CSS 动画实现樱花、雨、雪、萤火虫和蝴蝶飞舞背景效果,高性能且不影响 SEO
**1kB Series Lib** Fully functional with gzip code 1kB and keep source code readable
## Quick Start
### Setup
#### Node.js
```javascript
npm i yzhanweather
import YZhanWeather from 'yzhanweather'
```
#### Browser
```html
<script src="https://cdn.jsdelivr.net/npm/yzhanweather@latest/docs/yzhanweather.min.js"></script>
```
### Usage
```javascript
const yzhanweather = new YZhanWeather()
yzhanweather.run('firefly') // Options: sakura | snow | firefly | rain | butterfly
yzhanweather.run('firefly', {
maxDuration: 10 // Default: 10s, this option can determine the speed of animations
})
yzhanweather.clear() // Stop and clear all animations
yzhanweather.destory() // Destory the instance and free up memory
```
## Demo
[Online Demo](https://mantoufan.github.io/yzhanWeather/)
*Note: click the select on the left-top to change weather*
### GIF
sakura

snow

firefly

rain

butterfly

## Performance comparsion
We use a page from madfan including a 720P video background, collect data when rendering 40 butterflies at the same time.
- With Old Version
*Note: By GIF and JavaScript in **old** folder*

- With Pure CSS Version

No long tasks, almost negligible CPU and GPU usage
## Config
All config including speed, num and css tpl are in `conf.js` under the *src* folder.
You could change it and then `npm run build` your own version.
You can set `maxDuration` to control the speed of animations without changing the `conf.js`
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YZhan Weather Demo</title>
<style>
select {
opacity: .5
}
</style>
</head>
<body>
<div id="app">
<select>
<option value="bg/sakura.jpg">sakura</option>
<option value="bg/firefly.jpg">firefly</option>
<option value="bg/snow.jpg">snow</option>
<option value="bg/rain.jpg">rain</option>
<option value="bg/butterfly.jpg">butterfly</option>
</select>
<select>
<option value="5">3s</option>
<option value="6">6s</option>
<option value="10" selected>10s</option>
<option value="15">15s</option>
<option value="20">20s</option>
</select>
</div>
<script src="./yzhanweather.min.js"></script>
<script>
var yzhanweather = new YZhanWeather(), sels = document.getElementsByTagName('select')
function changeWallpaper() {
yzhanweather.run(sels[0].options[sels[0].selectedIndex].text, { maxDuration: sels[1].value })
document.body.style.cssText = 'background: rgba(0, 0, 0, 0) url(' + sels[0].value + ') no-repeat scroll center top / cover'
}
for (var i = 0; i < sels.length; i++) sels[i].onchange = changeWallpaper
changeWallpaper()
</script>
</body>
</html>
================================================
FILE: old/mtfWeather.js
================================================
(function () {
var d = 16,
os = false;
function of() {
var d = document.createElement("div");
return "undefined" !== typeof d.style["opacity"];
}
function g(a) {
a();
}
function h() {
var a = Object.create(null);
for (type in {
Top: "",
Left: "",
}) {
var b = type == "Top" ? "Y" : "X";
if (typeof window["page" + b + "Offset"] !== "undefined") {
a[type.toLowerCase()] = window["page" + b + "Offset"];
} else {
b = document.documentElement.clientHeight
? document.documentElement
: document.body;
a[type.toLowerCase()] = b["scroll" + type];
}
}
return a;
}
function l(s) {
var a = document.body,
b;
if (window.innerHeight) {
b = window.innerHeight;
} else if (a.parentElement.clientHeight) {
b = a.parentElement.clientHeight;
} else if (a && a.clientHeight) {
b = a.clientHeight;
}
return b - (s || 0) - d; // 安全距离,避免滚动条闪现
}
function w(s) {
return document.documentElement.clientWidth - (s || 0) - d; //安全距离,避免滚动条闪现
}
function i(a) {
this.create(a);
}
var j = false;
g(function () {
j = true;
});
var f = true,
m,
c = [];
window.mtfWeather = function (a, b) {
if (a === "play") {
f = true;
} else if (a === "stop") {
f = false;
} else {
if (j) {
os = of();
if (m) {
clearInterval(m);
}
m = setInterval(function () {
f && c.length < b && Math.random() < 0.1 && c.push(new i(a));
for (var e = h().top, d = c.length - 1; d >= 0; d--)
if (c[d])
if (
c[d].top < e ||
c[d].top > e + c[d].maxTop ||
(os && c[d].el.style.opacity < 0.01)
) {
c[d].remove();
c[d] = null;
c.splice(d, 1);
} else {
c[d].move();
c[d].draw();
}
}, 60);
} else
g(function () {
mtfWeather(a, b);
});
}
};
i.prototype = {
common: function (o) {
o.style.cssText =
"position:absolute;display:block;z-index:99999;width:" +
o.size +
"px;height:" +
o.size +
"px";
},
create: function (a) {
switch (a) {
case "雪":
this.el = cache.get(
"./mtf/mtfWeatherPic/snow" + Math.floor(Math.random() * 5) + ".gif"
);
this.el.size = (Math.random() * 40 + 10) | 0;
this.common(this.el);
this.maxLeft = w(this.el.size);
this.maxTop = l(this.el.size);
this.left = Math.random() * this.maxLeft;
this.top = h().top + 1;
this.angle = 1.5;
this.minAngle = 1.35;
this.maxAngle = 1.65;
this.angleDelta = 0.01;
this.speed = 2 + Math.random();
break;
case "蝴蝶":
this.el = cache.get(
"./mtf/mtfWeatherPic/butterfly" +
Math.floor(Math.random() * 5) +
".gif"
);
this.el.size = (Math.random() * 10 + 8) | 0;
this.common(this.el);
this.maxLeft = w(this.el.size);
this.maxTop = l(this.el.size);
this.left = Math.random() * this.maxLeft;
this.top = h().top + l() / Math.floor(1 + Math.random() * 3);
this.angle = 0;
this.minAngle = 0;
this.maxAngle = 2;
this.angleDelta = 0.01;
this.speed = 2.5 + Math.random();
break;
case "光":
this.el = document.createElement("div");
this.el.size = (parseInt(Math.random() * 20) + 20) | 0;
this.common(this.el);
this.el.innerHTML = "●";
this.el.style.color = "#f9f7bd";
this.el.style.fontSize = this.el.size + "px";
this.maxLeft = w(this.el.size);
this.maxTop = 99999999;
this.left = Math.random() * this.maxLeft;
this.top = h().top + l(this.el.size * 1.25);
this.angle = 0.5;
this.minAngle = 0.35;
this.maxAngle = 0.65;
this.angleDelta = 0.01 * Math.random();
this.speed = 2 + Math.random();
break;
case "雨":
this.el = document.createElement("div");
this.el.size = 12;
this.common(this.el);
this.el.innerHTML = "|";
this.el.style.color = "#FFFFFF";
this.el.style.fontSize = this.el.size + "px";
this.maxLeft = w(this.el.size);
this.maxTop = l(this.el.size);
this.left = Math.random() * this.maxLeft;
this.top = h().top + 1;
this.angle = 1.5;
this.minAngle = -0.25;
this.maxAngle = 0.25;
this.angleDelta = 0.01 * Math.random();
this.speed = 5 + Math.random();
break;
case "樱花":
default:
//默认樱花
this.el = cache.get(
"./mtf/mtfWeatherPic/sakura" +
Math.floor(Math.random() * 8) +
".gif"
);
this.el.size = (Math.random() * 8 + 10) | 0;
this.common(this.el);
this.maxLeft = w(this.el.size);
this.maxTop = l(this.el.size);
this.left = Math.random() * this.maxLeft;
this.top = h().top + 1;
this.angle = 1.5;
this.minAngle = 1.2;
this.maxAngle = 1.7;
this.angleDelta = 0.01 * Math.random();
this.speed = 2 + 1.5 * Math.random();
break;
}
if (os) {
this.el.style.opacity = 0.5 + Math.random() * 0.5;
}
document.body.appendChild(this.el);
},
move: function () {
if (this.angle < this.minAngle || this.angle > this.maxAngle) {
this.angleDelta = -this.angleDelta;
}
this.angle += this.angleDelta;
this.left += this.speed * Math.cos(this.angle * Math.PI);
this.top -= this.speed * Math.sin(this.angle * Math.PI);
if (this.left < 0) {
this.left = this.maxLeft;
} else if (this.left > this.maxLeft) {
this.left = 0;
}
},
draw: function () {
this.el.style.top = Math.round(this.top) + "px";
this.el.style.left = Math.round(this.left) + "px";
if (os) {
this.el.style.opacity -= 0.003;
}
},
remove: function () {
document.body.removeChild(this.el);
this.el = null;
},
};
var cache = {
h: Object.create(null),
get: function (src) {
var el = this.h[src];
if (!el) {
el = document.createElement("img");
el.src = src;
this.h[src] = el;
}
return el.cloneNode();
},
};
})();
================================================
FILE: package.json
================================================
{
"name": "yzhanweather",
"version": "1.0.5",
"description": "Pure CSS animation for sakura, rain, snow, firefly and butterfly effects, high performance without affecting SEO. 纯 CSS 动画实现樱花、雨、雪、萤火虫和蝴蝶飞舞背景效果,高性能且不影响 SEO",
"main": "docs/yzhanweather.min.js",
"files": [
"docs/yzhanweather.min.js"
],
"scripts": {
"build": "webpack --mode production",
"dev": "webpack-dev-server"
},
"repository": {
"type": "git",
"url": "git@mtf.github.com:mantoufan/yzhanWeather.git"
},
"keywords": [
"sakura",
"rain",
"snow",
"firefly",
"butterfly",
"pure",
"css",
"js",
"library",
"performance",
"SEO"
],
"author": "shonwu",
"license": "MIT",
"devDependencies": {
"@swc/core": "^1.3.0",
"swc-loader": "^0.2.3",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^5.2.1"
},
"dependencies": {}
}
================================================
FILE: src/conf.js
================================================
const tpl = {
container: {
style: `
position: fixed;
top: 0;
width: 100%;
height: 0;
display: flex;
justify-content: space-evenly;
pointer-events: none;
`
},
fall: {
styles: [
`animation-delay: .1s;
animation-duration: 4s`,
`animation-delay: .5s;
animation-duration: 5s`,
`animation-delay: .3s;
animation-duration: 3s;
animation-name: {keyframes2}`,
`animation-delay: .2s;
animation-duration: 3.5s;
animation-name: {keyframes1}`,
`animation-delay: .9s;
animation-duration: 3s;
animation-name: {keyframes1};
animation-duration: 4.5s`,
`animation-delay: .7s;
animation-duration: 5.5s;
animation-name: {keyframes1}`,
`animation-delay: .4s;
animation-duration: 3s`,
`animation-delay: .6s;
animation-duration: 4s;
animation-name: {keyframes1}`,
`animation-delay: .5s;
animation-duration: 5.5s;
animation-name: {keyframes2};`,
`animation-delay: .3s;`,
`animation-delay: .7s;
animation-duration: 3.5s`,
`animation-delay: .5s;
animation-duration: 4s`,
`animation-delay: .15s;
animation-duration: 6.5s;
animation-name: {keyframes2};`,
`animation-delay: .5s;
animation-duration: 6.5s;
animation-name: {keyframes3};`,
`animation-delay: .55s;
animation-duration: 5.5s;
animation-name: {keyframes3};`,
`animation-delay: .75s;
animation-duration: 7.5s;
animation-name: {keyframes3};`,
],
keyframes: [
`from {
opacity: .9;
}
to {
transform: translate(10vw, 100vh) rotateX(45deg);
opacity: .2;
}`,
`from {
opacity: .9;
}
to {
transform: translate(-10vw, 100vh) rotateY(45deg);
opacity: .2;
}`,
`from {
opacity: .9;
}
to {
transform: translate(5vw, 100vh) rotateX(-45deg);
opacity: .2;
}`,
`from {
opacity: .9;
}
to {
transform: translate(-5vw, 100vh) rotateX(-45deg);
opacity: .2;
}`
]
},
spread: {
keyframes: [
`from {
transform: translateY(50vh) rotateZ(55deg) skew(5deg, 5deg);
opacity: .1;
}
to {
transform: translate(10vw, -100%) rotateZ(45deg);
opacity: .9;
}`,
`from {
transform: translateY(50vh) rotateZ(-55deg) skew(5deg, 5deg);
opacity: .1;
}
to {
transform: translate(-10vw, -100%) rotateZ(-45deg);
opacity: .9;
}`,
`from {
transform: translateY(50vh) rotateZ(155deg) skew(-5deg, 5deg);
opacity: .1;
}
to {
transform: translate(10vw, 105vh) rotateZ(145deg);
opacity: .9;
}`,
`from {
transform: translateY(50vh) rotateZ(195deg) skew(-5deg, 5deg);
opacity: .1;
}
to {
transform: translate(-10vw, 105vh) rotateZ(185deg);
opacity: .9;
}`,
]
},
snow: {
style: `
width: .5vw;
height: .5vw;
border-radius: 50%;
background-color: white;
border: 1px solid #fefefe;
transform: translateY(-100%);
animation: {keyframes0} 6s linear infinite;
`,
}
}
export default {
sakura: {
num: 20,
containerStyle: tpl.container.style,
style: `
width: 1.5vw;
height: 1.5vh;
border-radius: 50% 0;
background-image: linear-gradient(to right, pink, white);
transform: translateY(-100%);
animation: {keyframes0} 5s linear infinite;
`,
styles: tpl.fall.styles,
keyframes: tpl.fall.keyframes
},
snow: {
num: 60,
containerStyle: tpl.container.style,
style: tpl.snow.style,
styles: tpl.fall.styles,
keyframes: tpl.fall.keyframes
},
rain: {
num: 60,
containerStyle: tpl.container.style,
style: `
width: .2vw;
height: 1vw;
border-radius: 30%;
background-color: rgba(255, 255, 255, .5);
transform: translateY(-100%);
animation: {keyframes0} 6s ease-in-out infinite;
`,
styles: tpl.fall.styles,
keyframes: tpl.fall.keyframes
},
firefly: {
num: 60,
containerStyle: tpl.container.style,
style: tpl.snow.style.replace('white', '#fff06b'),
styles: tpl.fall.styles,
keyframes: tpl.spread.keyframes
},
butterfly: {
num: 40,
containerStyle: tpl.container.style,
html: `
<div class="wing"></div>
<div class="wing"></div>
`,
style: {
'' : `
display: inline-block;
position: relative;
width: 1.25vw;
height: 1.25vw;
transform: translateY(-100%);
animation: {keyframes0} 6s linear infinite;
`,
'::after': `
position: absolute;
content: ' ';
background-color: lightgoldenrodyellow;
border-radius: 50%;
display: block;
left: .5vw;
width: .25vw;
height: .75vw;
`,
'.wing': `
position: absolute;
width: .75vw;
height: .75vw;
animation: wing .3s infinite ease-in-out alternate;
`,
'.wing:last-child': `
right: 0;
`,
'.wing:last-child::after': `
right: .125vw;
left: auto;
`,
'.wing::before': `
position: absolute;
content: ' ';
display: block;
width: .6vw;
height: .6vw;
background-color: lightyellow;
border-radius: 50%;
`,
'.wing::after': `
position: absolute;
content: ' ';
display: block;
top: .5vw;
left: .12vw;
width: .5vw;
height: .5vw;
background-color: lightyellow;
border-radius: 50%;
`
},
keyframe: {
'wing': `
from {
transform: scale(.9);
}
to {
transform: scale(1.1);
}`
},
styles: tpl.fall.styles,
keyframes: tpl.spread.keyframes
}
}
================================================
FILE: src/yzhanweather.js
================================================
import CONF from './conf'
export default class {
constructor() {
this.wrapper = document.createElement('DIV')
document.body.appendChild(this.wrapper)
this.styleSheet = this.wrapper.appendChild(document.createElement('STYLE')).sheet
this.container = this.wrapper.appendChild(document.createElement('DIV'))
}
uuid() {
return 'xxxxxxxxxx'.replace(/x/g, _ => (Math.random() * 16 | 0).toString(16))
}
createRules(rules, nameFn, ruleFn = v => v) {
const names = []
for (const rule of rules) {
const name = 'yz' + this.uuid()
names.push(name)
this.styleSheet.insertRule(`${nameFn(name)} { ${ruleFn(rule)} }`, 0)
}
return names
}
createRule(rule, nameFn) {
for (const name in rule) {
this.styleSheet.insertRule(`${nameFn(name)} { ${rule[name]} }`, 0)
}
}
createKeyfarme(rule) {
this.createRule(rule, n => '@keyframes ' + n)
}
createKeyfarmes(rules) {
return this.createRules(rules, n => '@keyframes ' + n)
}
createStyles(rules, nameFn, keyframeNames) {
return this.createRules(rules, nameFn, rule => rule.replace(/\{keyframes(\d+)\}/g, (_, p) => keyframeNames[p]))
}
processStyles(styles, fn) {
const n = styles.length
for (let i = 0; i < n; i++) {
const g = styles[i].match(/animation-duration:(?<duration>.*)/)
if (g === null) continue
fn(parseFloat(g.groups.duration), g.groups.duration, i)
}
}
replaceStyles(styles, config) {
let maxDuration = 0
this.processStyles(styles, duration => maxDuration < duration && (maxDuration = duration))
this.processStyles(styles, (duration, srcDuration, i) => {
const newDuration = (duration / maxDuration) * config.maxDuration
const dstDuration = srcDuration.replace(duration, newDuration)
styles[i] = styles[i].replace(srcDuration, dstDuration)
})
}
load(type, config) {
let {num, html, containerStyle, style, styles, keyframe = {}, keyframes} = CONF[type]
this.createKeyfarme(keyframe)
const keyframeNames = this.createKeyfarmes(keyframes)
if (typeof style === 'string') style = { '': style }
this.createStyles([style['']], n => '.' + (this.container.className = n) + ' div', keyframeNames)
this.createStyles([containerStyle], _ => '.' + this.container.className, keyframeNames)
this.createRule(style, n => '.' + this.container.className + ' div' + (n[0] === ':' ? '' : ' ') + n)
this.replaceStyles(styles, config)
const classNames = this.createStyles(styles, n => ' .' + this.container.className + ' .' + n, keyframeNames)
const fragement = document.createDocumentFragment()
for (let i = 0; i < num; i++) {
const div = document.createElement('DIV')
if (html) div.innerHTML = html
fragement.appendChild(div).className = classNames[i % classNames.length]
}
this.container.appendChild(fragement)
}
run(type, config = { maxDuration: 10 }) {
this.clear()
this.load(type, config)
}
clear() {
this.container.innerHTML = ''
while (this.styleSheet.cssRules.length) this.styleSheet.deleteRule(0)
}
destory() {
this.wrapper.remove()
this.wrapper = this.styleSheet = this.container = null
}
}
================================================
FILE: webpack.config.js
================================================
const { resolve } = require('path')
module.exports = {
mode: 'development',
entry: './src/yzhanweather.js',
output: {
filename: 'yzhanweather.min.js',
path: resolve('docs'),
library: 'YZhanWeather',
libraryTarget: 'umd',
libraryExport: 'default',
globalObject: 'this',
environment: {
arrowFunction: false,
bigIntLiteral: false,
const: false,
destructuring: false,
dynamicImport: false,
forOf: false,
module: false,
optionalChaining: false,
templateLiteral: false
}
},
module: {
rules: [
{
test: /\.js$/,
include: resolve('src'),
use: ['swc-loader']
}
]
},
devServer: {
hot: true,
open: true,
port: 3000,
static: resolve('docs'),
}
}
gitextract_im5qcwqy/ ├── .gitignore ├── .swcrc ├── LICENSE ├── README.md ├── docs/ │ └── index.html ├── old/ │ └── mtfWeather.js ├── package.json ├── src/ │ ├── conf.js │ └── yzhanweather.js └── webpack.config.js
SYMBOL INDEX (19 symbols across 2 files)
FILE: old/mtfWeather.js
function of (line 4) | function of() {
function g (line 8) | function g(a) {
function h (line 11) | function h() {
function l (line 29) | function l(s) {
function w (line 41) | function w(s) {
function i (line 44) | function i(a) {
FILE: src/yzhanweather.js
method constructor (line 3) | constructor() {
method uuid (line 9) | uuid() {
method createRules (line 12) | createRules(rules, nameFn, ruleFn = v => v) {
method createRule (line 21) | createRule(rule, nameFn) {
method createKeyfarme (line 26) | createKeyfarme(rule) {
method createKeyfarmes (line 29) | createKeyfarmes(rules) {
method createStyles (line 32) | createStyles(rules, nameFn, keyframeNames) {
method processStyles (line 35) | processStyles(styles, fn) {
method replaceStyles (line 43) | replaceStyles(styles, config) {
method load (line 52) | load(type, config) {
method run (line 70) | run(type, config = { maxDuration: 10 }) {
method clear (line 74) | clear() {
method destory (line 78) | destory() {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
{
"path": ".gitignore",
"chars": 12,
"preview": "node_modules"
},
{
"path": ".swcrc",
"chars": 72,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/swcrc\",\n \"minify\": false\n}"
},
{
"path": "LICENSE",
"chars": 1060,
"preview": "MIT License\n\nCopyright (c) 2023 馒头饭\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof thi"
},
{
"path": "README.md",
"chars": 2439,
"preview": "# yzhanWeather\n\n {\n var d = 16,\n os = false;\n function of() {\n var d = document.createElement(\"div\");\n return \"un"
},
{
"path": "package.json",
"chars": 914,
"preview": "{\n \"name\": \"yzhanweather\",\n \"version\": \"1.0.5\",\n \"description\": \"Pure CSS animation for sakura, rain, snow, firefly a"
},
{
"path": "src/conf.js",
"chars": 6096,
"preview": "const tpl = {\n container: {\n style: `\n position: fixed;\n top: 0;\n width: 100%;\n height: 0;\n "
},
{
"path": "src/yzhanweather.js",
"chars": 3206,
"preview": "import CONF from './conf'\nexport default class {\n constructor() {\n this.wrapper = document.createElement('DIV')\n "
},
{
"path": "webpack.config.js",
"chars": 794,
"preview": "const { resolve } = require('path')\nmodule.exports = {\n mode: 'development',\n entry: './src/yzhanweather.js',\n output"
}
]
About this extraction
This page contains the full source code of the mantoufan/yzhanWeather GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (22.2 KB), approximately 6.6k tokens, and a symbol index with 19 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.